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

  1. Remove the later duplicate mapping named in the error.
  2. If the duplicate was intentional (e.g. same input, different outputs), merge the outputs into one mapping.
  3. 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

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


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/89db39f35108e14c. Report an issue: GitHub.