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.

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.

Appendix: 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)