{"record":{"id":"8a641efd96ef301b","repo":"caddyserver/caddy","slug":"mapping-d-has-d-outputs-but-there-are-d-destina","errorCode":null,"errorMessage":"mapping %d has %d outputs but there are %d destinations defined","messagePattern":"mapping (.+?) has (.+?) outputs but there are (.+?) destinations defined","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddyhttp/map/map.go","lineNumber":117,"sourceCode":"\t\t// prevent confusing/ambiguous mappings\n\t\tif m.Input != \"\" && m.InputRegexp != \"\" {\n\t\t\treturn fmt.Errorf(\"mapping %d has both input and input_regexp fields specified, which is confusing\", i)\n\t\t}\n\n\t\t// prevent duplicate mappings\n\t\tinput := m.Input\n\t\tif m.InputRegexp != \"\" {\n\t\t\tinput = m.InputRegexp\n\t\t}\n\t\tif prev, ok := seen[input]; ok {\n\t\t\treturn fmt.Errorf(\"mapping %d has a duplicate input '%s' previously used with mapping %d\", i, input, prev)\n\t\t}\n\t\tseen[input] = i\n\n\t\t// ensure mappings have 1:1 output-to-destination correspondence\n\t\tnOut := len(m.Outputs)\n\t\tif nOut != nDest {\n\t\t\treturn fmt.Errorf(\"mapping %d has %d outputs but there are %d destinations defined\", i, nOut, nDest)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {\n\trepl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)\n\n\t// defer work until a variable is actually evaluated by using replacer's Map callback\n\trepl.Map(func(key string) (any, bool) {\n\t\t// return early if the variable is not even a configured destination\n\t\tdestIdx := slices.Index(h.Destinations, key)\n\t\tif destIdx < 0 {\n\t\t\treturn nil, false\n\t\t}\n\n\t\tinput := repl.ReplaceAll(h.Source, \"\")","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddyhttp/map/map.go#L99-L135","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add or remove outputs in the flagged mapping until they equal the number of destinations, in destination order.","Use \"-\" (null) for outputs you want to skip on a given mapping.","Recount after any change to the destinations list."],"exampleFix":"// before (Caddyfile)\nmap {host} {http.vars.up} {http.vars.tier} {\n  a.example.com prod\n}\n\n// after\nmap {host} {http.vars.up} {http.vars.tier} {\n  a.example.com prod 1\n}","handlingStrategy":"validation","validationCode":"func outputsMatchDestinations(mappings []Mapping, nDest int) bool {\n\tfor _, m := range mappings {\n\t\tif len(m.Outputs) != nDest {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Every mapping row fills every destination, in order.","Use '-' for intentionally blank outputs.","Re-verify all rows after adding a destination."],"tags":["caddy","config","map-handler","arity","validation"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}