caddyserver/caddy · error
mapping %d has a duplicate input '%s' previously used with m
Error message
mapping %d has a duplicate input '%s' previously used with mapping %d
What it means
Validate in the map handler tracks every mapping's input (exact or regexp) in a `seen` map and rejects duplicates, because later duplicates would shadow earlier ones. The message names the duplicate input and both mapping indices.
Source
Thrown at modules/caddyhttp/map/map.go:110
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] = i
// ensure mappings have 1:1 output-to-destination correspondence
nOut := len(m.Outputs)
if nOut != nDest {
return fmt.Errorf("mapping %d has %d outputs but there are %d destinations defined", i, nOut, nDest)
}
}
return nil
}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
// defer work until a variable is actually evaluated by using replacer's Map callback
repl.Map(func(key string) (any, bool) {View on GitHub (pinned to 50e54ee279)
Solutions
- Remove the later duplicate mapping named in the error.
- If the duplicate was intentional (e.g. same input, different outputs), merge the outputs into one mapping.
- Lint generated map configs for duplicate keys before deploy.
Example fix
// before (Caddyfile)
map {host} {http.vars.up} {
a.example.com app1
a.example.com app2
}
// after
map {host} {http.vars.up} {
a.example.com app1
} Defensive patterns
Strategy: validation
Validate before calling
func noDuplicateInputs(mappings []Mapping) bool {
seen := map[string]bool{}
for _, m := range mappings {
k := m.Input
if m.InputRegexp != "" {
k = m.InputRegexp
}
if seen[k] {
return false
}
seen[k] = true
}
return true
} Prevention
- Deduplicate map inputs when generating configs.
- Remember regexp patterns compare by their literal pattern string.
When it happens
Trigger: Two mappings with input "foo", or one mapping input "foo" and another input_regexp "foo" (regexp inputs are compared by their pattern string).
Common situations: Large map blocks maintained by several people; merging map fragments from different sites; patterns that differ only in whitespace so they look distinct but hash the same after formatting.
Related errors
- destination must be a placeholder and only a placeholder
- %d destinations != %d defaults
- mapping %d has both input and input_regexp fields specified,
- mapping %d has %d outputs but there are %d destinations defi
- parsing listener address: %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/89db39f35108e14c.
Report an issue: GitHub.