gohugoio/hugo · error
operator argument must be string type
Error message
operator argument must be string type
What it means
parseWhereArgs received two trailing arguments, meaning the third positional argument to `where` must be an operator string ("==", "!=", "in", "like", ...), but args[0] failed the string type assertion. Hugo requires the operator to be a literal string to dispatch the comparison.
Source
Thrown at tpl/collections/where.go:396
kv := reflect.ValueOf(elemName)
if kv.Type().AssignableTo(obj.Type().Key()) {
return obj.MapIndex(kv), nil
}
return zero, fmt.Errorf("%s isn't a key of map type %s", elemName, typ)
}
return zero, fmt.Errorf("%s is neither a struct field, a method nor a map element of type %s", elemName, typ)
}
// parseWhereArgs parses the end arguments to the where function. Return a
// match value and an operator, if one is defined.
func parseWhereArgs(args ...any) (mv reflect.Value, op string, err error) {
switch len(args) {
case 1:
mv = reflect.ValueOf(args[0])
case 2:
var ok bool
if op, ok = args[0].(string); !ok {
err = errors.New("operator argument must be string type")
return
}
op = strings.TrimSpace(strings.ToLower(op))
mv = reflect.ValueOf(args[1])
default:
err = errors.New("can't evaluate the array by no match argument or more than or equal to two arguments")
}
return
}
// elemResolver resolves a sub-element from a reflect.Value.
// Built once before the loop to avoid repeated type checks and reflect.ValueOf allocations.
type elemResolver func(reflect.Value) (reflect.Value, error)
// newElemResolver returns a resolver optimized for the given element type and path.
// Returns nil if optimization isn't possible, in which case the caller should
// fall back to evaluateSubElem.
func (ns *Namespace) newElemResolver(ctxv reflect.Value, elemType reflect.Type, path []string) elemResolver {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Quote the operator: `where .Pages "Params.weight" ">=" 10`.
- Check argument order: key, operator, match value — operator third.
- If templating the operator, ensure the variable is a string (`printf "%s" $op`).
Example fix
<!-- before -->
{{ range where .Site.RegularPages "Params.weight" 5 10 }}
<!-- after -->
{{ range where .Site.RegularPages "Params.weight" ">=" 10 }} Defensive patterns
Strategy: type-guard
Validate before calling
{{ $op := "ge" }}
{{ if not (eq (printf "%T" $op) "string") }}{{ errorf "where operator must be a string" }}{{ end }} Type guard
{{/* only pass literal operator strings: "==", "!=", ">=", "in", "intersect", ... */}} Prevention
- Pass the operator as a quoted string literal ("ge", "in"), not a variable of another type
- When the operator comes from config/params, cast with string or validate its type first
- Use the 2-arg form (implicit ==) when no operator is needed
When it happens
Trigger: `where COLLECTION KEY OPERATOR MATCH` where OPERATOR is not a string — e.g. `where .Pages "Params.weight" 1 10` (a number in the operator slot), or passing a variable that holds a non-string.
Common situations: Forgetting to quote the operator (`>=` unquoted parses oddly), swapping operator and match argument order, generating the call via `partial` params where the operator became a number or bool.
Related errors
- can't evaluate the array by no match argument or more than o
- need at least 2 arguments to append
- must provide a Resource and optionally an options map
- can't iterate over %T
- invalid intersect values
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/2ec9fb27aba1ebca.json.
Report an issue: GitHub ↗.