Hmbown/CodeWhale · error · Error
Pet tape exceeds 64 MiB.
Error message
Pet tape exceeds 64 MiB.
What it means
Thrown by decodePetJSONL before parsing when the raw JSONL text is larger than 64 MiB (64 * 1024 * 1024 chars). It is an input-size guard: the caller passed a pet tape file whose byte/char length exceeds the accepted ceiling, so decoding is refused up front instead of attempting to split and parse an oversized payload.
Solutions
- Split the tape into ≤64 MiB chunks and decode each with decodePetJSONL separately
- Rotate or truncate the telemetry file at the writer so a single tape stays under the cap
- Stream/parse line-by-line yourself and call validatePetBucket per row instead of decodePetJSONL
- Delete or archive old tape files
Example fix
// before
const buckets = decodePetJSONL(fs.readFileSync(tapePath, 'utf8'));
// after
const text = fs.readFileSync(tapePath, 'utf8');
const buckets = text.length <= 64*1024*1024 ? decodePetJSONL(text)
: text.split('\n').reduce((acc, line) => acc.concat(decodePetJSONL(line + '\n')), []); Defensive patterns
Strategy: try-catch
Validate before calling
if (text.length > 64 * 1024 * 1024) {
// split into chunks before calling decodePetJSONL
}
const ok = text.length <= 64 * 1024 * 1024; Type guard
null
Try / catch
try {
buckets = decodePetJSONL(text);
} catch (e) {
if (e.message === 'Pet tape exceeds 64 MiB.') {
buckets = chunkText(text, 16 * 1024 * 1024).flatMap(decodePetJSONL);
} else throw e;
} Prevention
- Rotate tape files daily or at a size threshold well below 64 MiB
- Check file size before reading it fully into memory
- Stream large tapes instead of bulk-reading
When it happens
Trigger: Calling decodePetJSONL with a tape string whose .length exceeds 67,108,864 characters — e.g. reading an entire multi-day telemetry file into memory.
Common situations: A telemetry file grew past 24h/64MiB because the pet writer never rotated; a user pointed the loader at the wrong (much larger) log; concatenating many days of tapes before decoding.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- Live pet input exceeds its tail limit.
- MCP exceeded the -byte aggregate catalog limit
- Pet input exceeds 250000 events.
- Pet input exceeds 250000 events.
- Pet tape exceeds 24 hours.
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/8384854b91f1a150.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/core/pet-telemetry.ts:34
agentIds: string[];
waiting: boolean;
}
export function validatePetBucket(value: unknown): asserts value is PetBucket {
validatePetState(value);
const b = value as PetBucket;
if (!b || typeof b !== 'object' || b.version !== 1 || !Number.isSafeInteger(b.sequence) || b.sequence < 0 || b.sequence > PET_MAX_SECONDS * 2.5
|| b.simTimeMs !== b.sequence * PET_BIN_MS || b.durationMs !== PET_BIN_MS
|| !CATEGORIES.includes(b.channel as Category) || typeof b.waiting !== 'boolean'
|| !Array.isArray(b.agentIds) || b.agentIds.length > 250_000 || b.agentIds.some(id => typeof id !== 'string' || !id || id.length > 4096)
|| !Number.isSafeInteger(b.errors) || b.errors < 0 || b.errors > 250_000
|| !Array.isArray(b.onsets) || b.onsets.length !== 13 || b.onsets.some(n => !Number.isSafeInteger(n) || n < 0 || n > 250_000)
|| !Array.isArray(b.activeMs) || b.activeMs.length !== 13 || b.activeMs.some(n => !Number.isFinite(n) || n < 0 || n > 100_000_000))
throw new Error('Invalid version 1 pet bucket.');
}
export function decodePetJSONL(text: string): PetBucket[] {
if (text.length > 64 * 1024 * 1024) throw new Error('Pet tape exceeds 64 MiB.');
const rows = text.split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line) as unknown);
if (rows.length > 216_000) throw new Error('Pet tape exceeds 24 hours.');
return rows.map((row, i) => { validatePetBucket(row); if (row.sequence !== i) throw new Error('Non-contiguous pet tape.'); return row; });
}
/** A live file must advance before its contents count as a new observation.
* Existing bytes, duplicate samples and a restarted sequence establish a
* baseline; they never replay an old onset or human request. Drivers supply a
* bounded tail and reset this cursor after suspension or a new attachment. */
export class PetLiveTape {
private sequence: number | undefined;
reset(): void { this.sequence = undefined; }
readTail(text: string): PetBucket | undefined {
if (!text) { this.reset(); return; }
if (text.length > 262_144) { this.reset(); throw new Error('Live pet input exceeds its tail limit.'); }
if (!text.endsWith('\n')) return;
const line = text.trimEnd().split('\n').at(-1);
if (!line) return;View on GitHub (pinned to 433685b202)