{"record":{"id":"fd477f9e9770096d","repo":"caddyserver/caddy","slug":"s-array-index-out-of-bounds-s-fd477f","errorCode":null,"errorMessage":"[/%s] array index out of bounds: %s","messagePattern":"\\[/(.+?)\\] array index out of bounds: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"admin.go","lineNumber":1325,"sourceCode":"\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\n// would be to delete them from the raw, map[string]any\n// representation as they are indexed, then iterate the index we made\n// and add them back after encoding as JSON, but this is simpler.)\nfunc RemoveMetaFields(rawJSON []byte) []byte {","sourceCodeStart":1307,"sourceCodeEnd":1343,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/admin.go#L1307-L1343","documentation":"Thrown while traversing an intermediate array when the numeric index is negative or >= the array length. Unlike the final-segment case, there is no PUT append allowance here: intermediate hops must land on an existing element. The message includes the traversed prefix and the bad index.","triggerScenarios":"GET /config/apps/http/servers/myserver/routes/3/... when the routes array has fewer elements; any path that indexes past the end of an intermediate array such as match sets or handler lists.","commonSituations":"0-based vs 1-based confusion; stale indexes after elements were deleted or the config reloaded with fewer entries; paths generated from a template with an unfilled or default index.","solutions":["GET the array at the failing prefix to see its actual length, then use a valid 0..len-1 index","Recompute indexes after any DELETE that shifts subsequent elements","Generate paths programmatically from the live config instead of hardcoding indexes"],"exampleFix":"# before (only 1 route exists)\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/2/handle/0\n# after\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/0/handle/0","handlingStrategy":"validation","validationCode":"prefix=\"apps/http/servers/myserver/routes\"\nn=$(curl -s \"http://localhost:2019/config/$prefix\" | jq 'length')\nassert 0 <= idx < n, f'index {idx} out of range for array of {n}'","typeGuard":null,"tryCatchPattern":"On out-of-bounds during traversal, GET the prefix from the error message, recompute a valid index, and retry the full path once; persistent failure means your path model is wrong.","preventionTips":["Recompute indexes after any DELETE shifts array elements","Derive deep paths from live config rather than templates with fixed indexes"],"tags":["caddy","admin-api","config","array","bad-request"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}