{"record":{"id":"27a11f76498165fa","repo":"Hmbown/CodeWhale","slug":"invalid-pet-raster-size","errorCode":null,"errorMessage":"Invalid pet raster size.","messagePattern":"Invalid pet raster size\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":120,"sourceCode":"    }\n    advanceEngine(timeMs, motion, waiting) {\n        const target = Math.floor(timeMs * 30 / 1000 + 1e-8);\n        if (!Number.isFinite(timeMs) || target < this.engineTick || target - this.engineTick > 300)\n            throw new Error('Engine pet clock jump.');\n        this.engine.confirmWaiting(timeMs, waiting);\n        const voices = [];\n        while (this.engineTick < target) {\n            if ((this.engineTick + 1) % 12 === 0)\n                this.world.acceptTelemetry(this.engine.bucket(Math.floor(this.engineTick / 12)));\n            this.world.step(1 / 30, { motion, sensitivity: 1 });\n            voices.push(...this.world.voices);\n            this.engineTick++;\n        }\n        this.world.voices = voices;\n    }\n    terminal(width, height) {\n        if (![width, height].every(n => Number.isSafeInteger(n) && n >= 1 && n <= 512))\n            throw new Error('Invalid pet raster size.');\n        const { sim, frame } = this.world, l = (0, pet_sim_js_1.layout)(width * 2, height * 4, frame.state);\n        const cells = Array(width * height).fill(0), bits = [[1, 8], [2, 16], [4, 32], [64, 128]];\n        sim.p.forEach((p, i) => {\n            if (frame.state.observed < .92 && i % 2 === 1)\n                return;\n            const x = Math.round(l.ox + p.x * l.scale * l.flipX), y = Math.round(l.oy + p.y * l.scale);\n            if (x >= 0 && x < width * 2 && y >= 0 && y < height * 4)\n                cells[Math.floor(y / 4) * width + Math.floor(x / 2)] |= bits[y % 4][x % 2];\n        });\n        return JSON.stringify({ width, height, cells, timeMs: frame.timeMs, channel: frame.state.channel, arch: pet_sim_js_1.ARCH_OF[frame.state.channel],\n            hollow: frame.state.observed < .92, dozing: frame.behaviour === 'doze', lit: frame.state.lit });\n    }\n    pcmChannels(voicesJSON, startSample, length, rate) {\n        const p = (0, pet_audio_js_1.renderPetPCM)(JSON.parse(voicesJSON), startSample, length, rate);\n        return [p.left, p.right];\n    }\n    pcm(voicesJSON, startSample, length, rate) {\n        return JSON.stringify(this.pcmChannels(voicesJSON, startSample, length, rate).map(channel => Array.from(channel)));","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L102-L138","documentation":"The `browser` tool is an action-dispatch wrapper: its `action` field must be one of start, status, navigate, click, type, screenshot, or stop. Any other value — including typos, casing variants, or compound actions — falls through the switch and throws, with the offending value embedded via JSON.stringify.","triggerScenarios":"resolveTool(\"browser\", {action:\"open\"}), {action:\"Start\"} (capitalized), {action:\"close\"} instead of \"stop\", {action:\"scroll\"} (not supported), or action missing entirely (undefined shows as undefined in the message).","commonSituations":"Model hallucinating browser actions from other automation APIs (scroll/back/forward); camelCase or capitalized action names from generated code; assuming a back/forward history action exists; passing the wrong tool's action set.","solutions":["Use exactly one of: start, status, navigate, click, type, screenshot, stop — lowercase.","Map unsupported intents to supported ones: 'close' → stop, 'open' → start or navigate, 'scroll' → key/mouse tools.","Check the error message's `got ...` value to see what was actually passed (JSON.stringify of args.action)."],"exampleFix":"// before\nresolveTool(\"browser\", { action: \"open\", url: \"https://example.com\" });\n// after\nresolveTool(\"browser\", { action: \"navigate\", url: \"https://example.com\" });","handlingStrategy":"try-catch","validationCode":"const BROWSER_ACTIONS = [\"start\",\"status\",\"navigate\",\"click\",\"type\",\"screenshot\",\"stop\"];\nif (!BROWSER_ACTIONS.includes(args.action)) {\n  throw new Error(`browser action must be one of ${BROWSER_ACTIONS.join(\", \")}`);\n}","typeGuard":"const isBrowserAction = (a) =>\n  [\"start\",\"status\",\"navigate\",\"click\",\"type\",\"screenshot\",\"stop\"].includes(a);","tryCatchPattern":"try {\n  resolveTool(\"browser\", args);\n} catch (e) {\n  if (String(e.message).startsWith(\"browser action must be\")) {\n    // log args.action and retry with a mapped/corrected action\n  } else throw e;\n}","preventionTips":["Validate action against the enum list before calling; lowercase and normalize model output.","Map foreign-API names: open→start/navigate, close→stop; scroll/back do not exist here.","Read the `got ...` suffix in the message to see exactly what leaked through."],"tags":["argument-validation","enum-value","browser-automation"],"backgroundTag":"invalid-enum-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}