{"record":{"id":"e2079184e920bd8f","repo":"toon-format/toon","slug":"no-root-value-built-from-events","errorCode":null,"errorMessage":"No root value built from events","messagePattern":"No root value built from events","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/toon/src/decode/event-builder.ts","lineNumber":180,"sourceCode":"          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  }\n\n  if (state.root === undefined) {\n    throw new Error('No root value built from events')\n  }\n\n  return state.root\n}\n\n// #endregion\n","sourceCodeStart":162,"sourceCodeEnd":187,"githubUrl":"https://github.com/toon-format/toon/blob/604eac266e35166bed6f5b9e3bd586e9c60a9330/packages/toon/src/decode/event-builder.ts#L162-L187","documentation":"The event stream was balanced (stack empty at finalize) but no value was ever assigned to state.root, which happens only when zero events or no root-producing events were provided. The builder cannot return anything meaningful, so it throws instead of returning undefined.","triggerScenarios":"Calling buildValueFromEvents / buildValueFromEventsAsync with an empty (or root-less) event iterable — e.g. decoding an empty string, an iterable that yields nothing, or a producer that emits only container events that all get popped without setting a root (impossible for valid streams, but possible with only end events filtered).","commonSituations":"Decoding empty files, empty HTTP bodies, or blank TOON input; an upstream decode step that produced zero events; passing a filtered event stream where all events were removed.","solutions":["Check that the input TOON document is non-empty before decoding","Verify the event producer actually yields events (log the count before building)","Handle empty input explicitly at the call site (return a default value instead of decoding)","If decoding untrusted input, catch this and treat it as invalid/empty payload"],"exampleFix":"// before\nconst value = buildValueFromEvents(events) // throws if events is empty\n// after\nconst first = iterator.next()\nif (first.done) return null\nconst value = buildValueFromEvents([first.value, ...rest])","handlingStrategy":"validation","validationCode":"async function hasEvents(iterable) {\n  for await (const _ of iterable) return true\n  return false\n}\n// call before building; skip decode when it returns false","typeGuard":null,"tryCatchPattern":"try {\n  const value = buildValueFromEvents(events)\n} catch (err) {\n  if (err instanceof Error && err.message.includes('No root value built')) {\n    return null // or a default value for empty input\n  } else throw err\n}","preventionTips":["Check the raw input is non-empty and non-whitespace before decoding","Log event counts in pipelines to catch producers yielding nothing","Handle empty payloads upstream (return null/default) instead of decoding"],"tags":["streaming","events","toon","empty-input"],"backgroundTag":"empty-input","analyzedSha":"604eac266e35166bed6f5b9e3bd586e9c60a9330","analyzedAt":"2026-08-31T11:09:25.043Z","schemaVersion":2},"datasetVersion":"2026-09-01T08:17:40.651Z"}