caddyserver/caddy · error
invalid traversal path at: %s
Error message
invalid traversal path at: %s
What it means
Thrown when a traversal step lands on a config node that is neither a map nor an array — typically a scalar (string, number, bool) — yet the path continues with more segments. The message names the prefix up to and including the offending segment, e.g. 'invalid traversal path at: apps/http/servers/myserver/listen' when something like /0 is appended after listen.
Source
Thrown at admin.go:1331
v[part] = make(map[string]any)
}
ptr = v[part]
}
case []any:
partInt, err := parseCanonicalArrayIndex(part)
if err != nil {
return fmt.Errorf("[/%s] invalid array index '%s': %v",
strings.Join(parts[:i+1], "/"), part, err)
}
if partInt < 0 || partInt >= len(v) {
return fmt.Errorf("[/%s] array index out of bounds: %s",
strings.Join(parts[:i+1], "/"), part)
}
ptr = v[partInt]
default:
return fmt.Errorf("invalid traversal path at: %s", strings.Join(parts[:i+1], "/"))
}
}
return nil
}
// RemoveMetaFields removes meta fields like "@id" from a JSON message
// by using a simple regular expression. (An alternate way to do this
// would be to delete them from the raw, map[string]any
// representation as they are indexed, then iterate the index we made
// and add them back after encoding as JSON, but this is simpler.)
func RemoveMetaFields(rawJSON []byte) []byte {
return idRegexp.ReplaceAllFunc(rawJSON, func(in []byte) []byte {
// matches with a comma on both sides (when "@id" property is
// not the first or last in the object) need to keep exactly
// one comma for correct JSON syntax
comma := []byte{','}
if bytes.HasPrefix(in, comma) && bytes.HasSuffix(in, comma) {View on GitHub (pinned to 50e54ee279)
Solutions
- GET the exact prefix from the error message to see the node's actual type
- End the path at the scalar, e.g. .../listen/0 instead of .../listen/0/x
- Cross-check against the JSON config schema docs for leaf node types
Example fix
# before: '0' is a string leaf, cannot descend further curl http://localhost:2019/config/apps/http/servers/myserver/listen/0/x # after curl http://localhost:2019/config/apps/http/servers/myserver/listen/0
Defensive patterns
Strategy: type-guard
Validate before calling
prefix="apps/http/servers/myserver/listen" type=$(curl -s "http://localhost:2019/config/$prefix" | jq -r 'type') [ "$type" = "object" -o "$type" = "array" ] && echo "traversable" || echo "leaf — stop here"
Type guard
func traversable(v any) bool {
switch v.(type) {
case map[string]any, []any:
return true
}
return false
} Try / catch
Parse 'invalid traversal path at: <prefix>', GET that prefix to see its JSON type, and truncate or correct the path so it stops at or correctly indexes that node.
Prevention
- Know your schema: leaves like listen/0 are strings and cannot be descended into
- When in doubt, GET each level incrementally while constructing the path
When it happens
Trigger: GET /config/apps/http/servers/myserver/listen/0 where listen is a JSON array of strings but the scalar case occurs for e.g. .../automatic_https/disable/next, or any path that keeps descending after reaching a string/number/bool leaf such as .../listen/0/extra.
Common situations: Misjudging the config schema depth: treating a leaf scalar as a traversable container; appending extra segments after a full address like admin/timeout/... ; paths built by naive splitting of a desired dotted path.
Related errors
- [%s] invalid array index '%s': %v
- [/%s] invalid array index '%s': %v
- decoding request body: %w, at offset %d
- decoding request body: %w
- no traversable path
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/45270feedc403e2d.
Report an issue: GitHub.