{"record":{"id":"ced83b143fe00a65","repo":"gohugoio/hugo","slug":"s-isn-t-a-key-of-map-type-s","errorCode":null,"errorMessage":"%s isn't a key of map type %s","messagePattern":"(.+?) isn't a key of map type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/collections/where.go","lineNumber":382,"sourceCode":"\t\treturn zero, fmt.Errorf(\"can't evaluate a nil pointer of type %s by a struct field or map key name %s\", typ, elemName)\n\t}\n\tobj = reflect.Indirect(obj)\n\tswitch obj.Kind() {\n\tcase reflect.Struct:\n\t\tft, ok := obj.Type().FieldByName(elemName)\n\t\tif ok {\n\t\t\tif ft.PkgPath != \"\" && !ft.Anonymous {\n\t\t\t\treturn zero, fmt.Errorf(\"%s is an unexported field of struct type %s\", elemName, typ)\n\t\t\t}\n\t\t\treturn obj.FieldByIndex(ft.Index), nil\n\t\t}\n\t\treturn zero, fmt.Errorf(\"%s isn't a field of struct type %s\", elemName, typ)\n\tcase reflect.Map:\n\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])","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/collections/where.go#L364-L400","documentation":"In the map branch of `evaluateSubElem` (where.go:377-382), Hugo builds a reflect.Value of the element name and tests `kv.Type().AssignableTo(obj.Type().Key())`. If the name's type is not assignable to the map's key type, the lookup cannot proceed and Hugo reports that the name is not a key of that map type. Note the name is always a string here, so this commonly means a non-string-keyed map.","triggerScenarios":"`{{ where $m \"42\" ... }}` against `map[int]string`; any map whose key type is not `string`, since the where key path is always string-derived.","commonSituations":"Filtering a `map[int]T` or `map[customType]T` by a string key from a template; assuming map keys are strings when they are integers.","solutions":["If you need integer keys, restructure the data into a slice of structs with string fields before templating.","Convert the map to `map[string]T` during data preparation.","Use a different filtering strategy (range + index) instead of `where` on a non-string-keyed map."],"exampleFix":"// before\n{{ where $m \"42\" \"==\" v }}  {{/* map[int]string */}}\n// after\n{{/* pre-convert to map[string]string or a slice of structs */}}\n{{ where $items \"ID\" \"==\" \"42\" }}","handlingStrategy":"validation","validationCode":"// Go-side: ensure maps used with `where` have string keys\nif t.Kind() == reflect.Map && t.Key().Kind() != reflect.String {\n    // convert to map[string]T or a slice of structs\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use string-keyed maps for anything filtered in templates.","Convert integer-keyed maps to slices of structs during data prep.","Remember the where key path is always string-derived."],"tags":["hugo","go-templates","where","reflection","map","type-mismatch"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}