caddyserver/caddy · error

mapping %d has %d outputs but there are %d destinations defi

Error message

mapping %d has %d outputs but there are %d destinations defined

What it means

Validate in the map handler enforces 1:1 correspondence between each mapping's `outputs` and the top-level `destinations`: every mapping must have exactly len(destinations) outputs. The message reports the mapping index, its output count, and the destination count.

Source

Thrown at modules/caddyhttp/map/map.go:117

		// 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) {
		// return early if the variable is not even a configured destination
		destIdx := slices.Index(h.Destinations, key)
		if destIdx < 0 {
			return nil, false
		}

		input := repl.ReplaceAll(h.Source, "")

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add or remove outputs in the flagged mapping until they equal the number of destinations, in destination order.
  2. Use "-" (null) for outputs you want to skip on a given mapping.
  3. Recount after any change to the destinations list.

Example fix

// before (Caddyfile)
map {host} {http.vars.up} {http.vars.tier} {
  a.example.com prod
}

// after
map {host} {http.vars.up} {http.vars.tier} {
  a.example.com prod 1
}
Defensive patterns

Strategy: validation

Validate before calling

func outputsMatchDestinations(mappings []Mapping, nDest int) bool {
	for _, m := range mappings {
		if len(m.Outputs) != nDest {
			return false
		}
	}
	return true
}

Prevention

When it happens

Trigger: destinations has 2 entries but a mapping lists 1 or 3 outputs; Caddyfile map line `example.com foo` under a map with two destination placeholders.

Common situations: Adding a second destination ({http.vars.b}) and updating only some mappings; deleting outputs from one mapping during cleanup; misunderstanding that every row must fill every destination.

Related errors


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