gohugoio/hugo · error

errWrongArgStructure

errWrongArgStructure

Error message

expected a map, a slice with an even number of elements, or an even number of scalar values, and each key must be a string

What it means

`collections.Querify` builds a URL query string and accepts exactly three input shapes: a single map, a single slice with an even number of elements, or an even number of scalar key/value arguments (tpl/collections/querify.go:31-64). `errWrongArgStructure` is returned when the single argument is some other type, or when the element/argument count is odd — because query strings are strictly key/value pairs.

Source

Thrown at tpl/collections/querify.go:25

//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package collections

import (
	"errors"
	"net/url"

	"github.com/gohugoio/hugo/common/hmaps"
	"github.com/spf13/cast"
)

var (
	errWrongArgStructure = errors.New("expected a map, a slice with an even number of elements, or an even number of scalar values, and each key must be a string")
	errKeyIsEmptyString  = errors.New("one of the keys is an empty string")
)

// Querify returns a URL query string composed of the given key-value pairs,
// encoded and sorted by key.
func (ns *Namespace) Querify(params ...any) (string, error) {
	if len(params) == 0 {
		return "", nil
	}

	if len(params) == 1 {
		switch v := params[0].(type) {
		case map[string]any: // created with collections.Dictionary
			return mapToQueryString(v)
		case hmaps.Params: // project configuration or page parameters
			return mapToQueryString(v)
		case []string:
			return stringSliceToQueryString(v)

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Count your arguments: every key needs a value — `querify "a" 1 "b" 2`.
  2. When building the input dynamically, use a dict instead of a slice so pairing is enforced: `querify (dict "a" 1 "b" 2)`.
  3. If passing one argument, make sure it's a map or an even-length slice, not a pre-built string.
  4. Debug with `{{ warnf "%v" $args }}` to inspect the actual shape at build time.

Example fix

<!-- before: odd number of args -->
{{ querify "page" 2 "sort" }}
<!-- after -->
{{ querify "page" 2 "sort" "date" }}
Defensive patterns

Strategy: validation

Validate before calling

{{/* querify accepts: a map, a slice with even length, or even scalar args with string keys */}}
{{ $kv := dict "page" 1 "sort" "date" }}
{{ $q := querify $kv }}
{{/* if using a slice: */}}
{{ if ne (mod (len $pairs) 2) 0 }}{{ errorf "querify: odd number of elements" }}{{ end }}

Type guard

{{ $ok := true }}
{{ range $i, $v := $pairs }}
  {{ if and (eq (mod $i 2) 0) (not (reflect.IsString $v)) }}{{ $ok = false }}{{ end }}
{{ end }}

Prevention

When it happens

Trigger: `{{ querify "a" 1 "b" }}` (odd argument count); `{{ querify (slice "a" "1" "b") }}` (odd-length slice); `{{ querify .Page }}` or any single argument that isn't a map or slice, such as a plain string or number.

Common situations: Building pagination or filter links and forgetting a value for the last key; passing a raw query string ("a=1&b=2") expecting parsing; passing `.Params` values of unexpected shape; templates that append conditionally to a slice and end up with an odd length.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/32526316911446eb.json. Report an issue: GitHub ↗.