{"record":{"id":"598a85b6954304de","repo":"Hmbown/CodeWhale","slug":"missing-engine-index","errorCode":null,"errorMessage":"Missing Engine index.","messagePattern":"Missing Engine index\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1746,"sourceCode":"        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':\n                start(`thinking:${index()}`, 'thinking', 'reasoning');\n                this.waiting = undefined;","sourceCodeStart":1728,"sourceCodeEnd":1764,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1728-L1764","documentation":"The index() helper in observe converts the required non-negative safe-integer e.index into a span key suffix for message/thinking events. It throws 'Missing Engine index.' when index is absent or not a safe integer. Note the fields-level check only validates index when present; this throw fires when an event kind that needs index (message_started, response_delta, message_complete, thinking_*) lacks it entirely.","triggerScenarios":"Sending message_started/message_complete/thinking_started/thinking_complete/response_delta without an index field; index present as undefined via an explicit property; index as a string ('3') or float (3.5) reaching this helper.","commonSituations":"A delta event stream where the first delta omits the message index; a producer switching from numeric to string ids after a protocol change; optional-chaining bugs leaving index undefined.","solutions":["Always attach a non-negative safe-integer index to message/thinking lifecycle and delta events","Parse the index at the bridge boundary with Number and validate Number.isSafeInteger before observing","Skip events that legitimately carry no index instead of forwarding them to these event kinds"],"exampleFix":"// before\ntelemetry.observe({ event: 'response_delta', channel: 'text' }, at); // no index\n// after\ntelemetry.observe({ event: 'response_delta', index: messageIndex, channel: 'text' }, at);","handlingStrategy":"validation","validationCode":"const NEEDS_INDEX = new Set(['message_started','message_complete','thinking_started','thinking_complete','response_delta']);\nif (NEEDS_INDEX.has(e.event) && !Number.isSafeInteger(e.index)) throw new Error('event requires index');","typeGuard":null,"tryCatchPattern":"try {\n  telemetry.observe(meta, at);\n} catch (err) {\n  if (err.message === 'Missing Engine index.') { console.warn('dropping event without index', meta); return; }\n  throw err;\n}","preventionTips":["Attach the message/thinking index to every lifecycle and delta event","Validate index with Number.isSafeInteger before observing","Never stringify the index — keep it numeric until the adapter converts it"],"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"}