{"record":{"id":"93a132c0ceaa0024","repo":"toon-format/toon","slug":"primitive-event-without-preceding-key-in-object","errorCode":null,"errorMessage":"Primitive event without preceding key in object","messagePattern":"Primitive event without preceding key in object","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/toon/src/decode/event-builder.ts","lineNumber":159,"sourceCode":"      const parent = stack[stack.length - 1]!\n      if (parent.type !== 'object') {\n        throw new Error('Key event outside of object context')\n      }\n\n      parent.currentKey = event.key\n\n      break\n    }\n\n    case 'primitive': {\n      if (stack.length === 0) {\n        state.root = event.value\n      }\n      else {\n        const parent = stack[stack.length - 1]!\n        if (parent.type === 'object') {\n          if (parent.currentKey === undefined) {\n            throw new Error('Primitive event without preceding key in object')\n          }\n          setOwnProperty(parent.obj, parent.currentKey, event.value)\n          parent.currentKey = undefined\n        }\n        else if (parent.type === 'array') {\n          parent.arr.push(event.value)\n        }\n      }\n\n      break\n    }\n  }\n}\n\nfunction finalizeState(state: BuildState): JsonValue {\n  if (state.stack.length !== 0) {\n    throw new Error('Incomplete event stream: unclosed objects or arrays')\n  }","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/toon-format/toon/blob/604eac266e35166bed6f5b9e3bd586e9c60a9330/packages/toon/src/decode/event-builder.ts#L141-L177","documentation":"The event-builder received a `primitive` event while the current container is an object whose `currentKey` is undefined. In TOON's stream-event contract every value inside an object must be preceded by a `key` event, so a primitive with no pending key is a malformed event stream and the builder aborts instead of silently dropping the value. This guards against producers that emit events out of order.","triggerScenarios":"Calling buildValueFromEvents (or the async variant) with an event iterable where a `primitive` event appears inside an object without a preceding `key` event — e.g. hand-written event generators, custom tokenizers, or a buggy custom encoder that skips key events.","commonSituations":"Developers writing custom TOON encoders or streaming pipelines that synthesize JsonStreamEvent sequences themselves; tools post-processing or filtering event streams and accidentally removing key events; version mismatches where an older producer emits a different event grammar than the decoder expects.","solutions":["Fix the event producer so every primitive inside an object is preceded by a `key` event","If you control the stream, log the events immediately before the failure to find the missing key","Use the official toon encode/decode APIs instead of hand-assembling events","If filtering/transforming event streams, ensure transforms preserve key/value pairing"],"exampleFix":"// before: events = [{type:'startObject'},{type:'primitive',value:42},{type:'endObject'}]\n// after:  events = [{type:'startObject'},{type:'key',key:'a'},{type:'primitive',value:42},{type:'endObject'}]","handlingStrategy":"validation","validationCode":"function isValidEventStream(events) {\n  let inObject = false, pendingKey = false\n  for (const e of events) {\n    if (e.type === 'startObject') { inObject = true; pendingKey = false }\n    else if (e.type === 'endObject') { inObject = false; pendingKey = false }\n    else if (e.type === 'key') { if (!inObject) return false; pendingKey = true }\n    else if (e.type === 'primitive') { if (inObject && !pendingKey) return false; pendingKey = false }\n  }\n  return true\n}","typeGuard":null,"tryCatchPattern":"try {\n  const value = buildValueFromEvents(events)\n} catch (err) {\n  if (err instanceof Error && err.message.includes('without preceding key')) {\n    // regenerate events or reject malformed stream\n  } else throw err\n}","preventionTips":["Always emit a key event before each value inside an object","Use toon's official encoder to produce events rather than hand-building them","Unit-test custom event producers against round-trip encode/decode","Validate event streams with a small checker before building"],"tags":["streaming","events","toon","decoder"],"backgroundTag":"malformed-event-stream","analyzedSha":"604eac266e35166bed6f5b9e3bd586e9c60a9330","analyzedAt":"2026-08-31T11:09:25.043Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}