en Error Handling - chiba233/yume-dsl-token-walker GitHub Wiki

Error Handling & Safety

Interpret | Exports | Home

How errors are reported, what safety guarantees the interpreter provides, and how to observe errors without stopping iteration.


onError — observe, don't suppress

InterpretRuleset.onError is called before an error is thrown. It does not suppress the error — the error is always rethrown after onError returns.

Use it to log, report, or collect errors while still letting them propagate:

import { createParser, createSimpleInlineHandlers } from "yume-dsl-rich-text";
import { interpretTokens, collectNodes } from "yume-dsl-token-walker";

const parser = createParser({
  handlers: createSimpleInlineHandlers(["bold"]),
  trackPositions: true,
});

const tokens = parser.parse("$$bold(hello)$$");

const errors: Error[] = [];

try {
  collectNodes(interpretTokens(tokens, {
    createText: (text) => text,
    interpret: (token) => {
      if (token.type === "bold") throw new Error("boom");
      return { type: "unhandled" };
    },
    onError: ({ error, phase, token, position }) => {
      errors.push(error);
      if (position) {
        console.error(
          `[${phase}] ${error.message} at line ${position.start.line}:${position.start.column}`,
        );
      }
    },
  }, undefined));
} catch {
  // errors[] now contains the observed error
}

position is forwarded from token.position — present when the upstream parser has trackPositions: true. It's a SourceSpan with start and end, each containing offset (zero-indexed), line (one-indexed), and column (one-indexed).


Error phases

Every error reported through onError has a phase field:

Phase Trigger
"interpret" interpret() throws, onUnhandled strategy function throws, or onUnhandled: "throw" fires
"flatten" flattenText fails (e.g. circular value detected)
"traversal" Structural error — text token has non-string value, or recursive token detected
"internal" Unexpected internal state (e.g. unknown result type)

Safety guarantees

Self-recursion detection

If a handler feeds a token back into interpretChildren referencing itself, the interpreter detects it and throws immediately — before it can blow the stack.

Internally, a WeakSet<TextToken> tracks which tokens are currently being interpreted. If the same token object appears again during its own interpretation, an error is thrown.

Circular value detection

flattenText tracks visited tokens per recursion path (not globally). This means:

  • Shared references are safe — the same token appearing in multiple branches is fine
  • True cycles throw — if a token's value chain loops back to itself, flattenText throws with a descriptive error

Text token validation

If a token has type === "text" but its value is not a string, the interpreter throws a "traversal" error instead of silently producing garbage.


Boundary note

The exported flattenText() function is a standalone utility — it does not go through onError. Only errors raised inside interpretTokens / interpretTokensAsync are observed by onError.

If you call flattenText(value) directly and it encounters a circular reference, it throws immediately without any observer.

⚠️ **GitHub.com Fallback** ⚠️