gohugoio/hugo · error
value has type %s; should be %s
Error message
value has type %s; should be %s
What it means
Thrown by prepareArg during map indexing when the supplied index value is valid but its reflect.Type is not AssignableTo the map's key type. This is a hard type mismatch — e.g. indexing map[int]V with a string, or map[string]V with an int. Both the actual type and expected type are named via %s.
Source
Thrown at tpl/collections/index.go:131
return nil, fmt.Errorf("can't index item of type %s", v.Type())
}
}
return v.Interface(), nil
}
// prepareArg checks if value can be used as an argument of type argType, and
// converts an invalid value to appropriate zero if possible.
//
// Copied from Go stdlib src/text/template/funcs.go.
func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
if !value.IsValid() {
if !canBeNil(argType) {
return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
}
value = reflect.Zero(argType)
}
if !value.Type().AssignableTo(argType) {
return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
}
return value, nil
}
// canBeNil reports whether an untyped nil can be assigned to the type. See reflect.Zero.
//
// Copied from Go stdlib src/text/template/exec.go.
func canBeNil(typ reflect.Type) bool {
switch typ.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
return true
}
return false
}
View on GitHub (pinned to 52c9bd7908)
Solutions
- Coerce the key to the map's key type: `{{ index $intMap (int $k) }}` or `{{ index $strMap (string $k) }}`.
- Align the map's declaration with the keys actually used.
- Standardize data ingestion so keys are consistently typed.
- Inspect both types in the error message to pick the correct coercion.
Example fix
// before
{{ index $intKeyedMap "5" }}
// after
{{ index $intKeyedMap (int "5") }} Defensive patterns
Strategy: type-guard
Validate before calling
func assignableMapKey(mapV reflect.Value, key any) (reflect.Value, error) {
kv := reflect.ValueOf(key)
if !kv.IsValid() || !kv.Type().AssignableTo(mapV.Type().Key()) {
return reflect.Value{}, fmt.Errorf("key %T not assignable to map key %s", key, mapV.Type().Key())
}
return kv, nil
} Type guard
func keyMatchesMap(m, key any) bool {
mv := reflect.ValueOf(m)
if mv.Kind() != reflect.Map { return false }
kv := reflect.ValueOf(key)
if !kv.IsValid() { return false }
return kv.Type().AssignableTo(mv.Type().Key())
} Prevention
- Coerce keys to the map's declared key type before indexing.
- Keep map key types consistent across data sources.
- Standardize ingestion so keys are uniformly typed.
- Read both types in the error to pick the right coercion.
When it happens
Trigger: Calling `{{ index $intKeyedMap "1" }}` (string vs int key), `{{ index $stringKeyedMap 42 }}` (int vs string), or `{{ index $map $someStruct }}` where the struct isn't the key type. prepareArg's AssignableTo check fails.
Common situations: JSON/CSV data ingestion where keys arrive as strings but the map is int-keyed (or vice versa), template author guesses the key type, or a partial receives a key whose type differs across callers.
Related errors
- cannot index slice/array with type %s
- can't index item of type %s
- value is nil; should be of type %s
- isset unable to use key of type %T as index
- type %T not supported
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/e5b2d3165bd94d05.
Report an issue: GitHub.