gohugoio/hugo · error
key must start with '/': %q
Error message
key must start with '/': %q
What it means
doctree.ValidateKey requires every non-root key to be rooted, i.e. begin with '/'. Hugo's doctree is a path-keyed radix tree over logical page paths ("/blog/post"); a relative key would silently land in the wrong part of the tree, so unrooted keys are rejected up front.
Source
Thrown at hugolib/doctree/support.go:118
// StopPropagation stops the propagation of the event.
func (e *Event[T]) StopPropagation() {
e.stopPropagation = true
}
// ValidateKey returns an error if the key is not valid.
func ValidateKey(key string) error {
if key == "" {
// Root node.
return nil
}
if len(key) < 2 {
return fmt.Errorf("too short key: %q", key)
}
if key[0] != '/' {
return fmt.Errorf("key must start with '/': %q", key)
}
if key[len(key)-1] == '/' {
return fmt.Errorf("key must not end with '/': %q", key)
}
return nil
}
// Event is used to communicate events in the tree.
type Event[T any] struct {
Name string
Path string
Source T
stopPropagation bool
}
type LockType intView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Prepend '/' or, better, use Hugo's path parsing helpers so keys are always rooted logical paths.
- Trace where the key is built and normalize once at that boundary rather than at each call site.
Example fix
// before
tree.Insert(section+"/"+slug, n)
// after
tree.Insert("/"+section+"/"+slug, n) Defensive patterns
Strategy: validation
Validate before calling
if !strings.HasPrefix(key, "/") {
key = "/" + key
} Type guard
func isValidTreeKey(key string) bool {
return len(key) >= 2 && strings.HasPrefix(key, "/") && !strings.HasSuffix(key, "/")
} Prevention
- Always build keys from a root-relative path with an explicit leading slash
- Use path.Join("/", segments...) so the leading '/' is guaranteed
- Assert isValidTreeKey(key) in tests covering every code path that constructs keys
- Avoid concatenating strings manually for tree keys; use one shared key-builder helper
When it happens
Trigger: Inserting or looking up a doctree node with a key like "blog/post" instead of "/blog/post" — e.g. building the key from path segments without prepending the leading slash.
Common situations: Internal Hugo development or embedding hugolib and feeding filesystem-relative paths straight into the tree; forgetting to run paths through Hugo's path normalization (paths.Parse) which produces rooted paths.
Related errors
- key must not end with '/': %q
- id must not contain backslashes
- too short key: %q
- redirects must have either From or FromRe set
- failed to create config from result: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/40357a179fb7f1de.json.
Report an issue: GitHub ↗.