caddyserver/caddy · error

[%s] array index out of bounds: %s

Error message

[%s] array index out of bounds: %s

What it means

Thrown when addressing an array element by index in the config where the index is outside the array: negative, or >= len(arr) for GET/POST-style access (PUT may use idx == len(arr) to append at the end, but never greater). The message includes the offending path and index.

Source

Thrown at admin.go:1221

traverseLoop:
	for i, part := range parts {
		switch v := ptr.(type) {
		case map[string]any:
			// if the next part enters a slice, and the slice is our destination,
			// handle it specially (because appending to the slice copies the slice
			// header, which does not replace the original one like we want)
			if arr, ok := v[part].([]any); ok && i == len(parts)-2 {
				var idx int
				if method != http.MethodPost {
					idxStr := parts[len(parts)-1]
					idx, err = parseCanonicalArrayIndex(idxStr)
					if err != nil {
						return fmt.Errorf("[%s] invalid array index '%s': %v",
							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)

View on GitHub (pinned to 50e54ee279)

Solutions

  1. GET the parent array first and confirm its length; valid GET/DELETE/PATCH indices are 0..len-1
  2. For PUT, len(arr) is valid and appends; anything larger is rejected
  3. If elements were removed concurrently, re-fetch and recompute the index

Example fix

# before (only 2 routes exist)
curl -X DELETE http://localhost:2019/config/apps/http/servers/myserver/routes/3
# after
curl -X DELETE http://localhost:2019/config/apps/http/servers/myserver/routes/1
Defensive patterns

Strategy: validation

Validate before calling

parent="http://localhost:2019/config/apps/http/servers/myserver/routes"
n=$(curl -s "$parent" | jq 'length')
idx=1
[ "$idx" -ge 0 ] && [ "$idx" -lt "$n" ] && curl "$parent/$idx"

Prevention

When it happens

Trigger: GET /config/apps/http/servers/myserver/routes/5 when only 2 routes exist; DELETE with index == len(arr); negative indices like .../routes/-1.

Common situations: Off-by-one errors assuming 1-based indexing (Caddy is 0-based); stale index after another client deleted an element; using PUT index len(arr)+1 expecting append.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/ead8556c5a245188. Report an issue: GitHub.