{"record":{"id":"e967ff56304c6848","repo":"Hmbown/CodeWhale","slug":"missing-engine-field","errorCode":null,"errorMessage":"Missing Engine ${field}.","messagePattern":"Missing Engine (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1744,"sourceCode":"    }\n    observe(value, at) {\n        if (!Number.isFinite(at) || at < this.lastTime || at > pet_sim_js_1.PET_MAX_SECONDS * 1000)\n            throw new Error('Invalid Engine pet clock.');\n        if (!value || typeof value !== 'object' || Array.isArray(value))\n            throw new Error('Invalid Engine pet metadata.');\n        const e = value;\n        const allowed = ['event', 'index', 'channel', 'tool_call_id', 'tool_name', 'id', 'worker_status', 'failed'];\n        if (Object.keys(e).some(k => !allowed.includes(k)) || typeof e.event !== 'string'\n            || Object.values(e).some(v => typeof v === 'string' && v.length > 4096)\n            || e.channel !== undefined && !['text', 'reasoning'].includes(e.channel)\n            || ['tool_call_id', 'tool_name', 'id', 'worker_status'].some(k => e[k] !== undefined && typeof e[k] !== 'string')\n            || e.failed !== undefined && typeof e.failed !== 'boolean'\n            || e.index !== undefined && (!Number.isSafeInteger(e.index) || e.index < 0))\n            throw new Error('Invalid Engine pet metadata fields.');\n        this.lastTime = at;\n        this.events = this.events.filter(span => span.endTime >= at - 12_800);\n        const id = (field) => { const s = e[field]; if (typeof s !== 'string' || !s)\n            throw new Error(`Missing Engine ${field}.`); return s; };\n        const index = () => { if (!Number.isSafeInteger(e.index))\n            throw new Error('Missing Engine index.'); return String(e.index); };\n        const start = (key, name, category, agentId) => {\n            if (this.active.size >= 256 && !this.active.has(key))\n                throw new Error('Too many active Engine pet spans.');\n            this.active.set(key, this.add(name, category, at, agentId));\n        };\n        const finish = (key) => { this.pulse(key, at); this.active.delete(key); };\n        switch (e.event) {\n            case 'turn_started':\n                this.active.clear();\n                this.waiting = undefined;\n                break;\n            case 'message_started':\n                start(`message:${index()}`, 'assistant_message', 'communication');\n                this.waiting = undefined;\n                break;\n            case 'thinking_started':","sourceCodeStart":1726,"sourceCodeEnd":1762,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1726-L1762","documentation":"Inside observe, the id(field) helper extracts a required string identifier (tool_call_id, tool_name, or id) for events that need one. It throws `Missing Engine ${field}.` when the field is absent, not a string, or an empty string. The template makes the exact field name part of the message, e.g. 'Missing Engine tool_call_id.'","triggerScenarios":"Sending tool_call_started/tool_call_complete without tool_call_id or tool_name; sending agent_spawned/agent_progress/agent_complete without id; passing an empty-string identifier (id('') fails the !s check); passing a numeric id where a string is required.","commonSituations":"A protocol producer omitting the id on synthetic heartbeat/complete events; an id of 0 or a number from a JSON bridge not being stringified; empty tool names from unnamed tool wrappers.","solutions":["Always include the required string fields: tool_call_id and tool_name for tool events, id for agent events","Stringify numeric ids at the bridge boundary (String(id))","Skip or repair events with empty identifiers before feeding telemetry","Check which field name appears in the message and fix the producer for that specific field"],"exampleFix":"// before\ntelemetry.observe({ event: 'tool_call_started', tool_name: 'shell' }, at); // no tool_call_id\n// after\ntelemetry.observe({ event: 'tool_call_started', tool_call_id: String(callId), tool_name: 'shell' }, at);","handlingStrategy":"validation","validationCode":"function requireString(e, field) {\n  const s = e[field];\n  if (typeof s !== 'string' || !s) throw new Error(`Missing Engine ${field}.`);\n  return s;\n}\n// call before observe for events needing ids\nif (e.event.startsWith('tool_call_')) requireString(e, 'tool_call_id');","typeGuard":null,"tryCatchPattern":"try {\n  telemetry.observe(meta, at);\n} catch (err) {\n  const m = err.message.match(/^Missing Engine (\\w+)\\.$/);\n  if (m) { console.warn(`engine event missing ${m[1]}`, meta); return; }\n  throw err;\n}","preventionTips":["Always send tool_call_id and tool_name with tool events","Always send id with agent events","Stringify numeric ids at the bridge boundary","Reject empty-string identifiers at ingestion"],"tags":["telemetry","missing-field","validation"],"backgroundTag":"missing-required-argument","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"}