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] = i

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Make len(defaults) == len(destinations): one default per destination, in order.
  2. If you truly want no default, omit the defaults array entirely.
  3. 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

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


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