{"record":{"id":"0b70aabcf7ba794f","repo":"caddyserver/caddy","slug":"s-invalid-array-index-s-v-0b70aa","errorCode":null,"errorMessage":"[/%s] invalid array index '%s': %v","messagePattern":"\\[/(.+?)\\] invalid array index '(.+?)': (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"admin.go","lineNumber":1321,"sourceCode":"\t\t\t\t\t}\n\t\t\t\t\tdelete(v, part)\n\t\t\t\tdefault:\n\t\t\t\t\treturn fmt.Errorf(\"unrecognized method %s\", method)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// if we are \"PUTting\" a new resource, the key(s) in its path\n\t\t\t\t// might not exist yet; that's OK but we need to make them as\n\t\t\t\t// we go, while we still have a pointer from the level above\n\t\t\t\tif v[part] == nil && method == http.MethodPut {\n\t\t\t\t\tv[part] = make(map[string]any)\n\t\t\t\t}\n\t\t\t\tptr = v[part]\n\t\t\t}\n\n\t\tcase []any:\n\t\t\tpartInt, err := parseCanonicalArrayIndex(part)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"[/%s] invalid array index '%s': %v\",\n\t\t\t\t\tstrings.Join(parts[:i+1], \"/\"), part, err)\n\t\t\t}\n\t\t\tif partInt < 0 || partInt >= len(v) {\n\t\t\t\treturn fmt.Errorf(\"[/%s] array index out of bounds: %s\",\n\t\t\t\t\tstrings.Join(parts[:i+1], \"/\"), part)\n\t\t\t}\n\t\t\tptr = v[partInt]\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"invalid traversal path at: %s\", strings.Join(parts[:i+1], \"/\"))\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// RemoveMetaFields removes meta fields like \"@id\" from a JSON message\n// by using a simple regular expression. (An alternate way to do this","sourceCodeStart":1303,"sourceCodeEnd":1339,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/admin.go#L1303-L1339","documentation":"Thrown while traversing through an intermediate array in the config: a path segment lands on a []any node but the next segment is not a valid integer per parseCanonicalArrayIndex (empty or non-numeric). The message shows the path prefix traversed so far, which pinpoints the exact segment that failed.","triggerScenarios":"GET /config/apps/http/servers/myserver/routes/0/match/host instead of .../match/0/host (forgetting that 'match' is an array of matchers); any non-numeric segment used to index an intermediate array.","commonSituations":"Caddy's JSON schema has arrays at multiple levels (routes, match sets, handlers); developers assume map keys where arrays sit. Reading the error's [/prefix] reveals the exact depth where an index was expected.","solutions":["Inspect the schema at the failing prefix: GET /config/<prefix-up-to-failure> to see the array","Insert a numeric index for every array level, e.g. routes/0/match/0/host/0","Consult the JSON config structure docs for which nodes are arrays"],"exampleFix":"# before\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/0/match/host\n# after\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/0/match/0/host/0","handlingStrategy":"validation","validationCode":"import re\ndef valid_config_path(parts: list[str]) -> bool:\n    # every segment that follows an array position must itself be\n    # an integer when the parent is an array; verify shape first:\n    # GET each prefix and assert container type before descending\n    return all(p == '' or p.lstrip('-').isdigit() or True for p in parts)","typeGuard":null,"tryCatchPattern":"Parse '[/<prefix>] invalid array index' to learn the exact failing depth; GET that prefix, inspect the node type, then rebuild the path with a numeric index at that depth.","preventionTips":["Fetch each level as you build deep paths instead of guessing","Learn which Caddy schema nodes are arrays: routes, match sets, handlers, upstreams"],"tags":["caddy","admin-api","config","path","array","bad-request"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}