gohugoio/hugo · error
invalid dictionary key
Error message
invalid dictionary key
What it means
Dictionary (collections.go:170-189) accepts keys that are either a string or a []string (the latter for nested key paths). Any other key type (int, struct, map, etc.) hits the default branch at line 187-188.
Solutions
- Use string keys only
- Cast scalars: {{ dictionary (string .ID) "v" }}
- For nested paths use a slice of strings: {{ dictionary (slice "a" "b") "v" }}
Example fix
// before
{{ dictionary 1 "v" }}
// after
{{ dictionary "1" "v" }} Defensive patterns
Strategy: type-guard
Validate before calling
{{/* cast numeric/object keys to string */}}
{{ dictionary (string .ID) .Value }} Type guard
{{/* Go-side */}}
func isValidDictKey(v any) bool {
switch v.(type) {
case string, []string:
return true
}
return false
} Prevention
- Use only string keys (or []string for nested paths)
- Cast non-string keys with (string ...) first
- Never use structs, maps, or numbers as keys directly
When it happens
Trigger: {{ dictionary 1 "v" }} (int key), {{ dictionary .Page "v" }} (struct key), {{ dictionary .Params "v" }} (map key).
Common situations: Using a numeric ID as a key expecting coercion; passing a Page object as a key; passing a map as a key.
Related errors
- called apply using as type
- can't iterate over
- intersect does not support slices or arrays of uncomparable…
- argument must be a slice
- both limit and seq must be provided
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/9da14e1c327badf7.
Report an issue: GitHub.
Appendix: source
Thrown at tpl/collections/collections.go:188
switch v := values[i].(type) {
case string:
key = v
case []string:
for i := range len(v) - 1 {
key = v[i]
var m map[string]any
v, found := dict[key]
if found {
m = v.(map[string]any)
} else {
m = make(map[string]any)
dict[key] = m
}
dict = m
}
key = v[len(v)-1]
default:
return nil, errors.New("invalid dictionary key")
}
dict[key] = values[i+1]
}
return root, nil
}
// First returns the first limit items in list l.
func (ns *Namespace) First(limit any, l any) (any, error) {
if limit == nil || l == nil {
return nil, errors.New("both limit and seq must be provided")
}
limitv, err := cast.ToIntE(limit)
if err != nil {
return nil, err
}
View on GitHub (pinned to 52c9bd7908)