caddyserver/caddy · error
%d destinations != %d defaults
Error message
%d destinations != %d defaults
What it means
The map handler's Validate enforces that if `defaults` is non-empty its length equals the number of `destinations`, since each destination needs exactly one default value. A mismatch aborts config validation with both counts in the message.
Source
Thrown at modules/caddyhttp/map/map.go:94
}
var err error
h.Mappings[i].re, err = regexp.Compile(m.InputRegexp)
if err != nil {
return fmt.Errorf("compiling regexp for mapping %d: %v", i, err)
}
}
// TODO: improve efficiency even further by using an actual map type
// for the non-regexp mappings, OR sort them and do a binary search
return nil
}
// Validate ensures that h is configured properly.
func (h *Handler) Validate() error {
nDest, nDef := len(h.Destinations), len(h.Defaults)
if nDef > 0 && nDef != nDest {
return fmt.Errorf("%d destinations != %d defaults", nDest, nDef)
}
seen := make(map[string]int)
for i, m := range h.Mappings {
// prevent confusing/ambiguous mappings
if m.Input != "" && m.InputRegexp != "" {
return fmt.Errorf("mapping %d has both input and input_regexp fields specified, which is confusing", i)
}
// prevent duplicate mappings
input := m.Input
if m.InputRegexp != "" {
input = m.InputRegexp
}
if prev, ok := seen[input]; ok {
return fmt.Errorf("mapping %d has a duplicate input '%s' previously used with mapping %d", i, input, prev)
}
seen[input] = iView on GitHub (pinned to 50e54ee279)
Solutions
- Make len(defaults) == len(destinations): one default per destination, in order.
- If you truly want no default, omit the defaults array entirely.
- Re-count both arrays after editing the map block.
Example fix
// before (Caddyfile)
map {http.request.host} {http.vars.a} {http.vars.b} {
default one
}
// after
map {http.request.host} {http.vars.a} {http.vars.b} {
default one two
} Defensive patterns
Strategy: validation
Validate before calling
func balancedMapConfig(dests, defaults []string) bool {
if len(defaults) == 0 {
return true
}
return len(defaults) == len(dests)
} Prevention
- Update defaults whenever destinations change.
- Omit defaults entirely if none are needed.
- Treat map arity as a schema: destinations count drives every row.
When it happens
Trigger: map with 2 destinations and 3 defaults (or 1), e.g. destinations [{http.vars.a} {http.vars.b}] with defaults ["x"].
Common situations: Adding a destination later and forgetting the defaults; removing a destination while keeping old defaults; assuming defaults apply positionally to a single combined output.
Related errors
- mapping %d has %d outputs but there are %d destinations defi
- destination must be a placeholder and only a placeholder
- mapping %d has both input and input_regexp fields specified,
- mapping %d has a duplicate input '%s' previously used with m
- parsing listener address: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/e0b31f8613ae4ee1.
Report an issue: GitHub.