{"record":{"id":"6d177704cdf2b6fc","repo":"different-ai/openwork","slug":"invalid-ast-node-while-reading-context","errorCode":null,"errorMessage":"Invalid AST node while reading ${context}.","messagePattern":"Invalid AST node while reading (.+?)\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/interpreter/model.ts","lineNumber":161,"sourceCode":"    this.errorName = errorName\n    return this\n  }\n}\n\nexport const unsupportedSyntax = (kind: string, node: AstNode): InterpreterRuntimeError =>\n  new InterpreterRuntimeError(\n    `Syntax '${kind}' is not supported in CodeMode. ${supportedSyntaxMessage}`,\n    node,\n    \"UnsupportedSyntax\",\n    [supportedSyntaxMessage],\n  )\n\nexport const isRecord = (value: unknown): value is Record<string, unknown> =>\n  typeof value === \"object\" && value !== null\n\nexport const asNode = (value: unknown, context: string): AstNode => {\n  if (!isRecord(value) || typeof value.type !== \"string\") {\n    throw new InterpreterRuntimeError(`Invalid AST node while reading ${context}.`)\n  }\n  return value as AstNode\n}\n\nexport const getArray = (node: AstNode, key: string): Array<unknown> => {\n  const value = node[key]\n  if (!Array.isArray(value)) throw new InterpreterRuntimeError(`Expected '${key}' to be an array.`, node)\n  return value\n}\n\nexport const getString = (node: AstNode, key: string): string => {\n  const value = node[key]\n  if (typeof value !== \"string\") throw new InterpreterRuntimeError(`Expected '${key}' to be a string.`, node)\n  return value\n}\n\nexport const getBoolean = (node: AstNode, key: string): boolean => {\n  const value = node[key]","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/interpreter/model.ts#L143-L179","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the child exists before reading it (use getOptionalNode for optional fields)","Verify the AST comes from the parser version the interpreter expects; regenerate the parse","Log the `context` argument in the error message to find which AST access path produced the malformed value","If constructing nodes manually, always include { type: <nodeKind>, ... }"],"exampleFix":"// before\nconst target = asNode(node.expression, \"expression\") // undefined when absent\n// after\nconst target = node.expression !== undefined ? asNode(node.expression, \"expression\") : null","handlingStrategy":"type-guard","validationCode":"const looksLikeNode = (v: unknown): boolean =>\n  typeof v === \"object\" && v !== null && typeof (v as Record<string, unknown>).type === \"string\"\n// before reading a child: if (!node.body || !looksLikeNode(node.body)) skip","typeGuard":"const isAstNode = (v: unknown): v is AstNode =>\n  typeof v === \"object\" && v !== null && typeof (v as Record<string, unknown>).type === \"string\"","tryCatchPattern":"try {\n  const child = getNode(node, \"body\")\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.message.startsWith(\"Invalid AST node\")) {\n    logAstAnomaly(node) // capture offending subtree + context from message\n    return null\n  }\n  throw e\n}","preventionTips":["Pin parser and interpreter to compatible versions so AST shapes match","Always include a string `type` on hand-constructed nodes","Validate deserialized AST JSON with a schema (zod) before interpretation","Use getOptionalNode for fields that may legitimately be absent"],"tags":["ast","interpreter","type-narrowing"],"backgroundTag":"malformed-ast-node","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}