Hmbown/CodeWhale · error · Error
Native habitat exceeds 8 MiB.
Error message
Native habitat exceeds 8 MiB.
What it means
The `browser` tool's `click` action targets exactly one element: either a CSS `selector` or a screen `point` {x,y}. Supplying both a valid selector and a valid point is rejected because the library cannot know which target is intended.
Solutions
- Delete either `selector` or `point` so exactly one target remains.
- Prefer `selector` when you know the element; keep `point` only for canvas/coordinate-based UIs.
- If both values come from state, add a call-site branch that picks one deterministically (e.g. selector wins).
Example fix
// before
resolveTool("browser", { action: "click", selector: "#submit", point: { x: 100, y: 200 } });
// after
resolveTool("browser", { action: "click", selector: "#submit" }); Defensive patterns
Strategy: validation
Validate before calling
const hasSelector = typeof selector === "string" && selector.trim();
const hasPoint = point != null && Number.isFinite(point.x) && Number.isFinite(point.y);
if (hasSelector && hasPoint) {
delete args.point; // pick one target deterministically
} Type guard
const clickTargetOk = (a) => {
const s = typeof a.selector === "string" && a.selector.trim();
const p = a.point != null && Number.isFinite(a.point.x) && Number.isFinite(a.point.y);
return (s || p) && !(s && p);
}; Prevention
- Enforce one-target-per-click in your args builder: prefer selector, fall back to point.
- Don't merge click args from multiple sources without dropping the losing target field.
- Store recorded clicks as either selector or point, not both.
When it happens
Trigger: resolveTool("browser", {action:"click", selector:"#submit", point:{x:100,y:200}}) — both a non-empty string selector and a point with finite x and y present.
Common situations: Merging args from two clicks; a model hedging by giving both coordinate and selector; replaying a recorded click that stored both the resolved point and original selector; template that always fills both fields.
Related errors
- Choose one input source, an unused --output path (or…
- Engine pet clock jump.
- Invalid Engine batch.
- Invalid pet raster size.
- No pet segment was prepared.
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/cd931fb7db823aee.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tui/pet_watch/pet-native.js:76
this.world.acceptTelemetry(packet);
return true;
}
resetLiveInput() { this.liveTape.reset(); return this.resumeEngine(); }
recording(withCheckpoint = false) { return JSON.stringify(this.world.recording(withCheckpoint)); }
needsSegment() { return this.world.needsSegment; }
prepareSegment() { this.segment = this.world.prepareSegment(); return JSON.stringify(this.segment.recording); }
commitSegment() { if (!this.segment)
throw new Error('No pet segment was prepared.'); this.segment.commit(); this.segment = undefined; }
checkpoint() { return JSON.stringify(this.world.checkpoint()); }
recordingChunk(index, completed = false) { return this.world.recordingChunk(index, completed); }
restoreCheckpoint(text) {
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) {
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]);
this.world = pet_world_js_1.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 pet_engine_js_1.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() {
this.world.resumeObservation();
this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000);
this.engine = new pet_engine_js_1.PetEngineTelemetry();
this.world.voices = [];
return this.world.frame.timeMs;
}
observeEngine(metadataJSON, timeMs) { this.engine.observe(JSON.parse(metadataJSON), timeMs); }
observeEngineBatch(metadataJSON, timeMs) {View on GitHub (pinned to 73e0f67d83)