JuliusBrussee/caveman · error

array not closed

Error message

array not closed

What it means

readJSONTOONValue decodes a JSON array into a toonValue during TOON encoding. After consuming all element tokens it reads the next token and requires the ']' delimiter; if the token is not ']' (e.g. '}' or a value token), it means the JSON is malformed or truncated and the array was never closed, so encoding aborts with this error.

Solutions

  1. Validate the JSON with encoding/json (json.Valid or a decoder round-trip) before passing it to parseJSONTOON.
  2. Check the source of the data for truncation — incomplete file reads or cut-off HTTP bodies.
  3. Fix bracket balance in hand-authored JSON; run it through a linter/formatter.

Example fix

// before
encodeToonFromBytes(truncatedBody)
// after
if !json.Valid(truncatedBody) {
    return fmt.Errorf("invalid JSON input: %d bytes", len(truncatedBody))
}
encodeToonFromBytes(truncatedBody)
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid(input) {
    return fmt.Errorf("refusing TOON encode: input is not valid JSON")
}

Try / catch

v, err := parseJSONTOON(input)
if err != nil {
    if strings.Contains(err.Error(), "array not closed") {
        // log input offset and reject or re-fetch the payload
    }
    return err
}

Prevention

When it happens

Trigger: Calling parseJSONTOON on input where an array opened with '[' is never terminated with ']' — e.g. invalid JSON like "[1,2" or nested structure where a '}' or value token appears where ']' is required.

Common situations: Passing truncated JSON from a network stream or partial file read to the TOON encoder; hand-built JSON strings with mismatched brackets; upstream tools emitting broken JSON that bypassed prior validation.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/169919c4077bb5ea. Report an issue: GitHub.

Appendix: source

Thrown at engine/compressors/toon_encode.go:175

			if d, ok := end.(json.Delim); !ok || d != '}' {
				return toonValue{}, fmt.Errorf("object not closed")
			}
			return toonValue{kind: toonObject, obj: fields}, nil
		case '[':
			var arr []toonValue
			for dec.More() {
				val, err := readJSONTOONValue(dec)
				if err != nil {
					return toonValue{}, err
				}
				arr = append(arr, val)
			}
			end, err := dec.Token()
			if err != nil {
				return toonValue{}, err
			}
			if d, ok := end.(json.Delim); !ok || d != ']' {
				return toonValue{}, fmt.Errorf("array not closed")
			}
			return toonValue{kind: toonArray, arr: arr}, nil
		default:
			return toonValue{}, fmt.Errorf("unexpected delimiter %q", t)
		}
	case nil:
		return toonValue{kind: toonNull}, nil
	case bool:
		return toonValue{kind: toonBool, b: t}, nil
	case json.Number:
		return toonValue{kind: toonNumber, s: t.String()}, nil
	case string:
		return toonValue{kind: toonString, s: t}, nil
	default:
		return toonValue{}, fmt.Errorf("unsupported token %T", tok)
	}
}

View on GitHub (pinned to 3ee70a1026)