Hmbown/CodeWhale · error · Error
Native habitat exceeds 8 MiB.
Error message
Native habitat exceeds 8 MiB.
What it means
restoreRecording(text) replaces the whole native habitat from a serialized recording and enforces an 8 MiB cap on the input string. Recordings can legitimately be large (full telemetry tape plus state), so the ceiling is generous, but anything beyond it is treated as runaway growth or a wrong payload and rejected before parsing.
Solutions
- Trim the recording: drop old telemetry buckets and keep only recent state before restoring
- Use recordingChunk()/prepareSegment()+commitSegment() to persist incrementally instead of one giant blob
- Compress the recording before storing and decompress within the 8 MiB budget at restore time
- Verify you are restoring a single recording, not a concatenated or duplicated blob
Example fix
// before
pet.restoreRecording(entireSessionDump);
// after
const trimmed = pruneOldBuckets(entireSessionDump, /* keepMs */ 10 * 60 * 1000);
if (trimmed.length > 8 * 1024 * 1024) throw new Error('recording still too large; use chunked persistence');
pet.restoreRecording(trimmed); Defensive patterns
Strategy: validation
Validate before calling
function canRestoreRecording(text) { return typeof text === 'string' && text.length <= 8 * 1024 * 1024; } Try / catch
try {
pet.restoreRecording(text);
} catch (err) {
if (err.message === 'Native habitat exceeds 8 MiB.') {
pet.restoreRecording(compactRecording(text));
} else throw err;
} Prevention
- Persist incrementally with prepareSegment/commitSegment instead of one giant blob
- Cap live-session tape length with periodic pruning
- Compress recordings at rest and stay within the 8 MiB budget after decompression
When it happens
Trigger: Calling restoreRecording (directly or via restoreCheckpoint wrapping) with a string over 8*1024*1024 characters — typically an unbounded live tape that accumulated for a very long session, or concatenated multiple recordings.
Common situations: Very long-running live sessions whose JSONL tape grew past 8 MiB; accidental double-serialization of the same recording; archiving chunks into one giant string instead of using recordingChunk().
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
- bounded provider catalog cache exceeds its write limit
- bundle at is bytes; the limit is bytes
- choose one available display for recording
- download exceeds compressed size cap of bytes
- durationSec must be positive
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/1a282cdfe2721355.
Report an issue: GitHub.
Appendix: source
Thrown at pet/src/core/pet-native.ts:62
interactions(): string { return JSON.stringify(this.world.interactions); }
accept(packet: string): void { this.world.acceptTelemetry(JSON.parse(packet)); }
acceptLiveTail(text: string): boolean {
const packet = this.liveTape.readTail(text); if (!packet) return false;
this.world.acceptTelemetry(packet); return true;
}
resetLiveInput(): number { this.liveTape.reset(); return this.resumeEngine(); }
recording(withCheckpoint = false): string { return JSON.stringify(this.world.recording(withCheckpoint)); }
needsSegment(): boolean { return this.world.needsSegment; }
prepareSegment(): string { this.segment = this.world.prepareSegment(); return JSON.stringify(this.segment.recording); }
commitSegment(): void { if (!this.segment) throw new Error('No pet segment was prepared.'); this.segment.commit(); this.segment = undefined; }
checkpoint(): string { return JSON.stringify(this.world.checkpoint()); }
recordingChunk(index: number, completed = false): string | null { return this.world.recordingChunk(index, completed); }
restoreCheckpoint(text: string): void {
if (text.length > 512 * 1024) throw new Error('Pet checkpoint exceeds its size limit.');
this.restoreRecording(JSON.stringify({ ...this.world.recording(false), checkpoint: JSON.parse(text) }));
}
restoreRecording(text: string): void {
if (text.length > 8 * 1024 * 1024) throw new Error('Native habitat exceeds 8 MiB.');
const points = this.world.sim.p.map(p => [p.hx, p.hy] as [number, number]);
this.world = PetWorld.fromRecording(points, JSON.parse(text));
this.liveTape.reset();
this.segment = undefined; this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000); this.engine = new PetEngineTelemetry();
}
/** Resume a live host at the first unrecorded bucket. Keep every accepted
* interval, but never present its last observed frame as current evidence. */
resumeEngine(): number {
this.world.resumeObservation();
this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000);
this.engine = new PetEngineTelemetry();
this.world.voices = [];
return this.world.frame.timeMs;
}
observeEngine(metadataJSON: string, timeMs: number): void { this.engine.observe(JSON.parse(metadataJSON), timeMs); }
observeEngineBatch(metadataJSON: string, timeMs: number): void {
const events: unknown = JSON.parse(metadataJSON);
if (!Array.isArray(events) || events.length > 64) throw new Error('Invalid Engine batch.');View on GitHub (pinned to 433685b202)