JuliusBrussee/caveman · info

not valid TOON

Error message

not valid TOON

What it means

toonDecodeBytes was given bytes that DecodeTOON cannot parse as TOON. Decoding fails closed with an error — it never emits partial or guessed JSON — so malformed or truncated TOON input is surfaced rather than silently corrupted.

Source

Thrown at engine/cmd/caveman-engine/main.go:623

// toonEncodeBytes converts JSON to the lossless TOON subset. It fails closed:
// any input that is not valid JSON, or whose shape is outside the proven
// round-trip subset (deeply nested / non-uniform), returns an error rather than a
// lossy approximation — so the caller keeps JSON instead of trusting bad TOON.
func toonEncodeBytes(input []byte) ([]byte, error) {
	out, ok := compressors.NewTOON().Compress(input)
	if !ok {
		return nil, fmt.Errorf("not losslessly TOON-encodable (invalid JSON, or nested/non-uniform shape); keep JSON")
	}
	return out, nil
}

// toonDecodeBytes converts TOON back to compact JSON. Malformed TOON fails closed
// with an error; it never emits partial or guessed JSON.
func toonDecodeBytes(input []byte) ([]byte, error) {
	v, ok := compressors.DecodeTOON(input)
	if !ok {
		return nil, fmt.Errorf("not valid TOON")
	}
	out, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	return out, nil
}

func runEvals(args []string) {
	if len(args) < 1 || args[0] != "run" {
		fatal("usage: caveman-engine evals run [--fixtures DIR]")
	}
	fixtureDir := ""
	if len(args) == 3 && args[1] == "--fixtures" && args[2] != "" {
		fixtureDir = args[2]
	} else if len(args) != 1 {
		fatal("usage: caveman-engine evals run [--fixtures DIR]")
	}

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Verify the producer actually emitted TOON — remember encode intentionally falls back to JSON on unsupported shapes, so detect format first.
  2. Check the payload for truncation (compare lengths/hashes end to end).
  3. Keep producer and consumer on the same engine/compressors version.
  4. On error, surface it upstream rather than retrying blindly — the bytes are wrong, not the timing.

Example fix

// before
json_out, err := toonDecodeBytes(payload)

// after: sniff format, decode conditionally
var json_out []byte
if compressors.IsTOON(payload) { json_out, err = toonDecodeBytes(payload) } else { json_out = payload }
Defensive patterns

Strategy: type-guard

Type guard

func isTOON(b []byte) bool {
    _, ok := compressors.DecodeTOON(b)
    return ok
}

Try / catch

if out, err := toonDecodeBytes(payload); err != nil {
    // payload is not TOON: either plain JSON or corrupt; handle explicitly
    return handleNonTOON(payload)
} else {
    use(out)
}

Prevention

When it happens

Trigger: Calling toonDecodeBytes on data that is not TOON-encoded (e.g. still plain JSON because encoding fell back, or hand-mangled/truncated TOON).

Common situations: Round-trip asymmetry where encode fell back to JSON but the consumer assumes TOON; truncated payload from a transport; version skew between TOON writer and reader.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/40134ebf075effe9. Report an issue: GitHub.