{"record":{"id":"2ec9fb27aba1ebca","repo":"gohugoio/hugo","slug":"operator-argument-must-be-string-type","errorCode":null,"errorMessage":"operator argument must be string type","messagePattern":"operator argument must be string type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/where.go","lineNumber":396,"sourceCode":"\t\tkv := reflect.ValueOf(elemName)\n\t\tif kv.Type().AssignableTo(obj.Type().Key()) {\n\t\t\treturn obj.MapIndex(kv), nil\n\t\t}\n\t\treturn zero, fmt.Errorf(\"%s isn't a key of map type %s\", elemName, typ)\n\t}\n\treturn zero, fmt.Errorf(\"%s is neither a struct field, a method nor a map element of type %s\", elemName, typ)\n}\n\n// parseWhereArgs parses the end arguments to the where function.  Return a\n// match value and an operator, if one is defined.\nfunc parseWhereArgs(args ...any) (mv reflect.Value, op string, err error) {\n\tswitch len(args) {\n\tcase 1:\n\t\tmv = reflect.ValueOf(args[0])\n\tcase 2:\n\t\tvar ok bool\n\t\tif op, ok = args[0].(string); !ok {\n\t\t\terr = errors.New(\"operator argument must be string type\")\n\t\t\treturn\n\t\t}\n\t\top = strings.TrimSpace(strings.ToLower(op))\n\t\tmv = reflect.ValueOf(args[1])\n\tdefault:\n\t\terr = errors.New(\"can't evaluate the array by no match argument or more than or equal to two arguments\")\n\t}\n\treturn\n}\n\n// elemResolver resolves a sub-element from a reflect.Value.\n// Built once before the loop to avoid repeated type checks and reflect.ValueOf allocations.\ntype elemResolver func(reflect.Value) (reflect.Value, error)\n\n// newElemResolver returns a resolver optimized for the given element type and path.\n// Returns nil if optimization isn't possible, in which case the caller should\n// fall back to evaluateSubElem.\nfunc (ns *Namespace) newElemResolver(ctxv reflect.Value, elemType reflect.Type, path []string) elemResolver {","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/where.go#L378-L414","documentation":"When `where` is given two trailing arguments (operator + match value), the first must be a string so it can be used as the operator. `parseWhereArgs` at where.go:395 type-asserts `args[0].(string)`; if it fails (e.g. an int, struct, or slice is passed as the operator position), this error fires.","triggerScenarios":"Calling `{{ where .Pages \"Date\" 20240101 20241231 }}` where the operator position holds a number instead of a string operator, or passing a variable that is not a string in the operator slot.","commonSituations":"A developer intends a two-value comparison but forgets the operator string, effectively passing two match values. The second value lands in the operator position and fails the string assertion.","solutions":["Insert the operator string as the first trailing argument: `{{ where .Pages \"Date\" \"ge\" $startDate }}`.","If only a match value is intended (implicit equality), pass exactly one trailing argument: `{{ where .Pages \"Section\" \"blog\" }}`.","Verify the operator variable is always a string before the call."],"exampleFix":"// before\n{{ where .Pages \"Date\" $start $end }}\n// after\n{{ where .Pages \"Date\" \"ge\" $start }}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isStringOperator(args []any) bool {\n    if len(args) != 2 { return true }\n    _, ok := args[0].(string)\n    return ok\n}","tryCatchPattern":null,"preventionTips":["When passing two trailing args, the first must be a string operator.","For implicit equality, pass exactly one match value.","Double-check variable types in the operator slot."],"tags":["hugo","template","collections","where","type-error"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}