caddyserver/caddy · error
final element is not an array
Error message
final element is not an array
What it means
Thrown when POST targets an array destination with the '...' ellipsis form (path ends in '...') but the request body is not a JSON array. The ellipsis contract is: the parent is an array, the final path part is '...', and the payload must itself be an array whose elements are appended one by one.
Source
Thrown at admin.go:1235
path, idxStr, err)
}
if idx < 0 || (method != http.MethodPut && idx >= len(arr)) || idx > len(arr) {
return fmt.Errorf("[%s] array index out of bounds: %s", path, idxStr)
}
}
switch method {
case http.MethodGet:
err = enc.Encode(arr[idx])
if err != nil {
return fmt.Errorf("encoding config: %v", err)
}
case http.MethodPost:
if ellipses {
valArray, ok := val.([]any)
if !ok {
return fmt.Errorf("final element is not an array")
}
v[part] = append(arr, valArray...)
} else {
v[part] = append(arr, val)
}
case http.MethodPut:
// avoid creation of new slice and a second copy (see
// https://github.com/golang/go/wiki/SliceTricks#insert)
arr = append(arr, nil)
copy(arr[idx+1:], arr[idx:])
arr[idx] = val
v[part] = arr
case http.MethodPatch:
arr[idx] = val
case http.MethodDelete:
v[part] = append(arr[:idx], arr[idx+1:]...)
default:
return fmt.Errorf("unrecognized method %s", method)View on GitHub (pinned to 50e54ee279)
Solutions
- Wrap the payload in a JSON array: POST '[ { "handle": ... } ]' to .../routes/...
- Or drop the ellipsis and POST the single object directly to .../routes to append one element
Example fix
# before
curl -X POST http://localhost:2019/config/apps/http/servers/myserver/routes/... \
-d '{"handle":[{"handler":"static_response","body":"hi"}]}'
# after
curl -X POST http://localhost:2019/config/apps/http/servers/myserver/routes/... \
-d '[{"match":[{"host":["a.example"]}],"handle":[{"handler":"static_response","body":"hi"}]}]' Defensive patterns
Strategy: type-guard
Validate before calling
import json val = json.loads(body) assert isinstance(val, list), 'ellipsis (...) POST requires an array payload'
Type guard
func isJSONArray(body []byte) bool {
var v any
if json.Unmarshal(body, &v) != nil {
return false
}
_, ok := v.([]any)
return ok
} Prevention
- Pair '...' paths with array payloads by convention in your client library
- Single-element append: POST the object without the ellipsis instead
When it happens
Trigger: POST /config/apps/http/servers/myserver/routes/... with body '{"handle":[...]}' (an object) or '"x"' (a string). Only a JSON array payload is accepted, e.g. '[{...},{...}]'.
Common situations: Misreading the ellipsis feature and sending a single object to be wrapped; sending an array nested one level too deep or too shallow.
Related errors
- decoding request body: %w, at offset %d
- decoding request body: %w
- [%s] invalid array index '%s': %v
- [%s] array index out of bounds: %s
- [/%s] invalid array index '%s': %v
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/babda5b00dd37f64.
Report an issue: GitHub.