{"record":{"id":"7985e3d2f4bc11bf","repo":"toon-format/toon","slug":"array-startarray-event-without-preceding-key","errorCode":null,"errorMessage":"Array startArray event without preceding key","messagePattern":"Array startArray event without preceding key","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/toon/src/decode/event-builder.ts","lineNumber":104,"sourceCode":"\n      if (stack.length === 0) {\n        state.root = context.obj\n      }\n\n      break\n    }\n\n    case 'startArray': {\n      const arr: JsonValue[] = []\n\n      if (stack.length === 0) {\n        stack.push({ type: 'array', arr })\n      }\n      else {\n        const parent = stack[stack.length - 1]!\n        if (parent.type === 'object') {\n          if (parent.currentKey === undefined) {\n            throw new Error('Array startArray event without preceding key')\n          }\n          setOwnProperty(parent.obj, parent.currentKey, arr)\n          parent.currentKey = undefined\n        }\n        else if (parent.type === 'array') {\n          parent.arr.push(arr)\n        }\n\n        stack.push({ type: 'array', arr })\n      }\n\n      break\n    }\n\n    case 'endArray': {\n      if (stack.length === 0) {\n        throw new Error('Unexpected endArray event')\n      }","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/toon-format/toon/blob/604eac266e35166bed6f5b9e3bd586e9c60a9330/packages/toon/src/decode/event-builder.ts#L86-L122","documentation":"applyEvent received a startArray event while the parent is an object with no pending currentKey. Arrays inside objects must be assigned under a key, so the builder throws.","triggerScenarios":"A stream where startArray appears inside an object context without a preceding key event.","commonSituations":"Buggy event producers; manually written event sequences omitting keys before nested arrays.","solutions":["Emit a key event before startArray when inside an object","Fix the upstream tokenizer/emitter ordering","Validate key-before-value ordering in the stream beforehand"],"exampleFix":"// before\n[{type:'startObject'},{type:'startArray'},{type:'endArray'}]\n// after\n[{type:'startObject'},{type:'key',key:'items'},{type:'startArray'},{type:'endArray'}]","handlingStrategy":"validation","validationCode":"function keysPrecedeArrays(events) {\n  let inObject = false, expectKey = false\n  for (const ev of events) {\n    if (ev.type === 'startObject') { inObject = true; expectKey = false }\n    else if (ev.type === 'endObject') inObject = false\n    else if (ev.type === 'key') expectKey = true\n    else if (ev.type === 'startArray' && inObject && !expectKey) return false\n    else if (ev.type === 'endArray') expectKey = false\n  }\n  return true\n}","typeGuard":null,"tryCatchPattern":"try {\n  const value = buildValueFromEvents(events)\n} catch (e) {\n  if (e.message.includes('Array startArray event without preceding key')) {\n    throw new Error('Nested array emitted without a key in object context')\n  }\n  throw e\n}","preventionTips":["Emit a key event before startArray whenever the current parent is an object","Reuse the library's parser to generate streams where possible","Contract-test custom emitters with nested structures"],"tags":["event-stream","decoder","toon"],"backgroundTag":"malformed-event-stream","analyzedSha":"604eac266e35166bed6f5b9e3bd586e9c60a9330","analyzedAt":"2026-08-31T11:09:25.043Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}