Hmbown/CodeWhale · error · Error
Pet tape exceeds 64 MiB.
Error message
Pet tape exceeds 64 MiB.
What it means
decodePetJSONL enforces a hard 64 MiB limit on the raw tape text before parsing. The limit protects the iOS/JS bridge from unbounded memory use when a pet tape file grows beyond any legitimate 24-hour window. Files larger than the cap are rejected before any JSON parsing occurs.
Solutions
- Rotate or truncate the tape to a single <=24h window (max 216,000 rows) before loading.
- Split the file and decode only the most recent segment.
- Fix the producer to stop appending past one day's worth of bins.
- Pre-check file size in the caller and surface a friendly rotation message.
Example fix
// before const tape = await readFile(path, 'utf8'); const rows = decodePetJSONL(tape); // after const stat = await statFile(path); if (stat.size > 64 * 1024 * 1024) await rotateTape(path); const rows = decodePetJSONL(await readFile(path, 'utf8'));
Defensive patterns
Strategy: validation
Validate before calling
if (tapeText.length > 64 * 1024 * 1024) { rotateTape(); } else { decodePetJSONL(tapeText); } Type guard
const isDecodableTapeSize = (text) => typeof text === 'string' && text.length <= 64 * 1024 * 1024;
Try / catch
try { rows = decodePetJSONL(text); }
catch (e) { if (e.message === 'Pet tape exceeds 64 MiB.') { rotateTape(); rows = decodePetJSONL(readTail(path)); } else throw e; } Prevention
- Rotate the tape daily; never append across days.
- Stat the file size before loading and rotate proactively.
- Cap producer output to one 24h window.
- Test your rotation logic with an oversized fixture.
When it happens
Trigger: Calling decodePetJSONL with a string whose .length exceeds 67,108,864 characters — typically a tape file that accumulated rows for multiple days, was concatenated/append-only without rotation, or whose producer wrote far more buckets than the 216,000-row maximum.
Common situations: A long-running daemon appending to the same pet tape forever; a log-rotation misconfiguration; a developer pointing the loader at a combined/aggregated tape of several sessions.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- exceeds the byte workspace .env limit
- Input exceeds 64 MiB.
- legacy import refused: symlink or size bound
- MCP exceeded the -byte aggregate catalog limit
- Pet tape exceeds 64 MiB.
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/08a336c22ce09c78.
Report an issue: GitHub.
Appendix: source
Thrown at pet/ios/Resources/pet-native.js:1115
const pet_sim_js_1 = require("./pet-sim.js");
/** One projection for imports, demos and recorded live snapshots. Times are ms.
* These are aesthetic encodings of measured events, never model confidence. */
exports.PET_BIN_MS = 400;
function validatePetBucket(value) {
(0, pet_sim_js_1.validatePetState)(value);
const b = value;
if (!b || typeof b !== 'object' || b.version !== 1 || !Number.isSafeInteger(b.sequence) || b.sequence < 0 || b.sequence > pet_sim_js_1.PET_MAX_SECONDS * 2.5
|| b.simTimeMs !== b.sequence * exports.PET_BIN_MS || b.durationMs !== exports.PET_BIN_MS
|| !model_js_1.CATEGORIES.includes(b.channel) || 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.');
}
function decodePetJSONL(text) {
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));
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. */
class PetLiveTape {
sequence;
reset() { this.sequence = undefined; }
readTail(text) {
if (!text) {
this.reset();
return;
}View on GitHub (pinned to 433685b202)