toon-format/toon · error · Error

Key event outside of object context

Error message

Key event outside of object context

What it means

applyEvent received a key event while the stack is empty — no object is open, so the key has nowhere to belong. Keys are only valid inside an object context.

Source

Thrown at packages/toon/src/decode/event-builder.ts:138

      if (stack.length === 0) {
        throw new Error('Unexpected endArray event')
      }

      const context = stack.pop()!
      if (context.type !== 'array') {
        throw new Error('Mismatched endArray event')
      }

      if (stack.length === 0) {
        state.root = context.arr
      }

      break
    }

    case 'key': {
      if (stack.length === 0) {
        throw new Error('Key event outside of object context')
      }

      const parent = stack[stack.length - 1]!
      if (parent.type !== 'object') {
        throw new Error('Key event outside of object context')
      }

      parent.currentKey = event.key

      break
    }

    case 'primitive': {
      if (stack.length === 0) {
        state.root = event.value
      }
      else {
        const parent = stack[stack.length - 1]!

View on GitHub (pinned to 604eac266e)

Solutions

  1. Emit startObject before any key events
  2. Fix the producer so keys only occur inside object contexts
  3. Pre-validate that key events are nested in an open object

Example fix

// before
[{type:'key',key:'a'},{type:'string',value:'x'}]
// after
[{type:'startObject'},{type:'key',key:'a'},{type:'string',value:'x'},{type:'endObject'}]
Defensive patterns

Strategy: validation

Validate before calling

function keysOnlyInsideObject(events) {
  let objectDepth = 0
  for (const ev of events) {
    if (ev.type === 'startObject') objectDepth++
    else if (ev.type === 'endObject') objectDepth--
    else if (ev.type === 'key' && objectDepth === 0) return false
  }
  return objectDepth === 0
}

Try / catch

try {
  const value = buildValueFromEvents(events)
} catch (e) {
  if (e.message === 'Key event outside of object context') {
    throw new Error('Event stream emitted a key with no open object')
  }
  throw e
}

Prevention

When it happens

Trigger: A key event before any startObject, or after all contexts have closed, fed to buildValueFromEvents/Async.

Common situations: Producers emitting top-level keys; streams missing an initial startObject.

Related errors


AI-assisted analysis of toon-format/toon@604eac266e (2026-08-31). Data as JSON: /api/errors/947ef23f1728fce3. Report an issue: GitHub.