toon-format/toon · error · Error
Object startObject event without preceding key
Error message
Object startObject event without preceding key
What it means
applyEvent received a startObject event while the current parent is an object with no pending currentKey. Object values must be assigned under a key, so the builder throws to reject a malformed event stream.
Source
Thrown at packages/toon/src/decode/event-builder.ts:61
// #endregion
// #region Shared event handlers
function applyEvent(state: BuildState, event: JsonStreamEvent): void {
const { stack } = state
switch (event.type) {
case 'startObject': {
const obj: JsonObject = {}
if (stack.length === 0) {
stack.push({ type: 'object', obj })
}
else {
const parent = stack[stack.length - 1]!
if (parent.type === 'object') {
if (parent.currentKey === undefined) {
throw new Error('Object startObject event without preceding key')
}
setOwnProperty(parent.obj, parent.currentKey, obj)
parent.currentKey = undefined
}
else if (parent.type === 'array') {
parent.arr.push(obj)
}
stack.push({ type: 'object', obj })
}
break
}
case 'endObject': {
if (stack.length === 0) {
throw new Error('Unexpected endObject event')View on GitHub (pinned to 604eac266e)
Solutions
- Emit a key event before startObject when nesting inside an object
- Fix the upstream event producer's key-then-value ordering
- Validate the event stream before feeding it to buildValueFromEvents
Example fix
// before
const events = [{type:'startObject'},{type:'endObject'}]
// after
const events = [{type:'key',key:'a'},{type:'startObject'},{type:'endObject'}] Defensive patterns
Strategy: validation
Validate before calling
function keysPrecedeObjectValues(events) {
let inObject = false, expectKey = false
for (const ev of events) {
if (ev.type === 'startObject') { if (inObject && !expectKey) return false; inObject = true; expectKey = false }
else if (ev.type === 'endObject') inObject = false
else if (ev.type === 'key') expectKey = true
else expectKey = false
}
return true
} Try / catch
try {
const value = buildValueFromEvents(events)
} catch (e) {
if (e.message.includes('without preceding key')) {
throw new Error('Event stream violates key-before-value ordering: ' + e.message)
}
throw e
} Prevention
- Always emit a key event immediately before startObject when nesting in an object
- Derive event streams from encode()/the library parser rather than hand-building them
- Contract-test custom emitters against the builder
When it happens
Trigger: buildValueFromEvents/buildValueFromEventsAsync given a stream where startObject appears inside an object context without an intervening key event.
Common situations: Bugs in custom event emitters/tokenizers; hand-constructed event arrays in tests missing key events.
Related errors
- Unexpected endObject event
- Mismatched endObject event
- Array startArray event without preceding key
- Unexpected endArray event
- Mismatched endArray event
AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31).
Data as JSON: /api/errors/4c4e7f2ea5cf328c.
Report an issue: GitHub.