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

  1. Check that the input TOON document is non-empty before decoding
  2. Verify the event producer actually yields events (log the count before building)
  3. Handle empty input explicitly at the call site (return a default value instead of decoding)
  4. 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

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


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