different-ai/openwork · error · InterpreterRuntimeError

Invalid AST node while reading ${context}.

Error message

Invalid AST node while reading ${context}.

What it means

asNode narrows an unknown value to an AstNode before the interpreter reads properties off it. A valid node must be a non-null object with a string `type` field. Malformed AST fragments (primitives, null, objects missing `type`) throw InterpreterRuntimeError with the reading context included for debugging.

Source

Thrown at packages/codemode/src/interpreter/model.ts:161

    this.errorName = errorName
    return this
  }
}

export const unsupportedSyntax = (kind: string, node: AstNode): InterpreterRuntimeError =>
  new InterpreterRuntimeError(
    `Syntax '${kind}' is not supported in CodeMode. ${supportedSyntaxMessage}`,
    node,
    "UnsupportedSyntax",
    [supportedSyntaxMessage],
  )

export const isRecord = (value: unknown): value is Record<string, unknown> =>
  typeof value === "object" && value !== null

export const asNode = (value: unknown, context: string): AstNode => {
  if (!isRecord(value) || typeof value.type !== "string") {
    throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`)
  }
  return value as AstNode
}

export const getArray = (node: AstNode, key: string): Array<unknown> => {
  const value = node[key]
  if (!Array.isArray(value)) throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node)
  return value
}

export const getString = (node: AstNode, key: string): string => {
  const value = node[key]
  if (typeof value !== "string") throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node)
  return value
}

export const getBoolean = (node: AstNode, key: string): boolean => {
  const value = node[key]

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Check the child exists before reading it (use getOptionalNode for optional fields)
  2. Verify the AST comes from the parser version the interpreter expects; regenerate the parse
  3. Log the `context` argument in the error message to find which AST access path produced the malformed value
  4. If constructing nodes manually, always include { type: <nodeKind>, ... }

Example fix

// before
const target = asNode(node.expression, "expression") // undefined when absent
// after
const target = node.expression !== undefined ? asNode(node.expression, "expression") : null
Defensive patterns

Strategy: type-guard

Validate before calling

const looksLikeNode = (v: unknown): boolean =>
  typeof v === "object" && v !== null && typeof (v as Record<string, unknown>).type === "string"
// before reading a child: if (!node.body || !looksLikeNode(node.body)) skip

Type guard

const isAstNode = (v: unknown): v is AstNode =>
  typeof v === "object" && v !== null && typeof (v as Record<string, unknown>).type === "string"

Try / catch

try {
  const child = getNode(node, "body")
} catch (e) {
  if (e instanceof InterpreterRuntimeError && e.message.startsWith("Invalid AST node")) {
    logAstAnomaly(node) // capture offending subtree + context from message
    return null
  }
  throw e
}

Prevention

When it happens

Trigger: Calling asNode (directly or via getNode/getOptionalNode) with null, undefined, a primitive, an array, or an object lacking a string `type` — typically while traversing a parsed program, e.g. asNode(node.body, "statement body") where body is not a node.

Common situations: A parser/parser-version mismatch producing an AST shape the interpreter doesn't expect; hand-written or programmatically generated AST fragments missing `type`; deserialized JSON ASTs that lost the type field; optional child accessed when absent.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/6d177704cdf2b6fc. Report an issue: GitHub.