toon-format/toon · error · Error
No root value built from events
Error message
No root value built from events
What it means
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.
Source
Thrown at packages/toon/src/decode/event-builder.ts:180
parent.currentKey = undefined
}
else if (parent.type === 'array') {
parent.arr.push(event.value)
}
}
break
}
}
}
function finalizeState(state: BuildState): JsonValue {
if (state.stack.length !== 0) {
throw new Error('Incomplete event stream: unclosed objects or arrays')
}
if (state.root === undefined) {
throw new Error('No root value built from events')
}
return state.root
}
// #endregion
View on GitHub (pinned to 604eac266e)
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
Example fix
// before const value = buildValueFromEvents(events) // throws if events is empty // after const first = iterator.next() if (first.done) return null const value = buildValueFromEvents([first.value, ...rest])
Defensive patterns
Strategy: validation
Validate before calling
async function hasEvents(iterable) {
for await (const _ of iterable) return true
return false
}
// call before building; skip decode when it returns false Try / catch
try {
const value = buildValueFromEvents(events)
} catch (err) {
if (err instanceof Error && err.message.includes('No root value built')) {
return null // or a default value for empty input
} else throw err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Primitive event without preceding key in object
- Incomplete event stream: unclosed objects or arrays
- Top-level document must start with a key-value or array-head
- Indentation depth jump: expected depth ${parentDepth + 1}, b
- Unexpected bare token line outside root primitive position
AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31).
Data as JSON: /api/errors/e2079184e920bd8f.
Report an issue: GitHub.