{"record":{"id":"66d5c8635f3dd05e","repo":"caddyserver/caddy","slug":"s-invalid-array-index-s-v","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":1216,"sourceCode":"\t\tparts = parts[:len(parts)-1]\n\t}\n\n\tvar ptr any = rawCfg\n\ntraverseLoop:\n\tfor i, part := range parts {\n\t\tswitch v := ptr.(type) {\n\t\tcase map[string]any:\n\t\t\t// if the next part enters a slice, and the slice is our destination,\n\t\t\t// handle it specially (because appending to the slice copies the slice\n\t\t\t// header, which does not replace the original one like we want)\n\t\t\tif arr, ok := v[part].([]any); ok && i == len(parts)-2 {\n\t\t\t\tvar idx int\n\t\t\t\tif method != http.MethodPost {\n\t\t\t\t\tidxStr := parts[len(parts)-1]\n\t\t\t\t\tidx, err = parseCanonicalArrayIndex(idxStr)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"[%s] invalid array index '%s': %v\",\n\t\t\t\t\t\t\tpath, idxStr, err)\n\t\t\t\t\t}\n\n\t\t\t\t\tif idx < 0 || (method != http.MethodPut && idx >= len(arr)) || idx > len(arr) {\n\t\t\t\t\t\treturn fmt.Errorf(\"[%s] array index out of bounds: %s\", path, idxStr)\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tswitch method {\n\t\t\t\tcase http.MethodGet:\n\t\t\t\t\terr = enc.Encode(arr[idx])\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"encoding config: %v\", err)\n\t\t\t\t\t}\n\t\t\t\tcase http.MethodPost:\n\t\t\t\t\tif ellipses {\n\t\t\t\t\t\tvalArray, ok := val.([]any)\n\t\t\t\t\t\tif !ok {","sourceCodeStart":1198,"sourceCodeEnd":1234,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/admin.go#L1198-L1234","documentation":"Thrown during config traversal when the second-to-last path part resolves to an array (the destination), and the final part is used as an array index, but it is not a valid integer. parseCanonicalArrayIndex rejects empty strings and non-numeric values. Example: GET /config/apps/http/servers/myserver/routes/first.","triggerScenarios":"GET/PUT/PATCH/DELETE on /config/... where the last segment addresses an element of an array but is not a number, e.g. .../routes/new or .../routes/ (empty). POST is exempt because it appends.","commonSituations":"Assuming routes/keys are named maps when they are arrays in Caddy's JSON schema; using a human name or @id where a numeric index is required; trailing slash producing an empty final segment.","solutions":["Use a numeric zero-based index, e.g. .../routes/0","Check the shape first: GET the parent array (e.g. .../routes) and count elements","Prefer /id/<@id> addressing if you want name-based access to an array element"],"exampleFix":"# before\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/first\n# after\ncurl http://localhost:2019/config/apps/http/servers/myserver/routes/0","handlingStrategy":"validation","validationCode":"last = path.rstrip('/').split('/')[-1]\nassert last.lstrip('-').isdigit() and last != '', f'last segment must be an integer index, got {last!r}'","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember Caddy JSON arrays (routes, match sets, handlers) need numeric 0-based indices","Use /id/<@id> when you want name-based element addressing"],"tags":["caddy","admin-api","config","path","bad-request"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}