different-ai/openwork · error · InterpreterRuntimeError

Expected '${key}' to be a string.

Error message

Expected '${key}' to be a string.

What it means

getString reads a property off an AstNode and asserts it is a string, throwing InterpreterRuntimeError (node attached) otherwise. It guards literal values, identifiers, operator names, etc., so a non-string (undefined, number, object) means the AST node lacks or misnames the expected field.

Source

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

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]
  if (typeof value !== "boolean") throw new InterpreterRuntimeError(`Expected '${key}' to be a boolean.`, node)
  return value
}

export const getOptionalNode = (node: AstNode, key: string): AstNode | undefined => {
  const value = node[key]
  if (value === undefined || value === null) return undefined
  return asNode(value, key)
}

export const getNode = (node: AstNode, key: string): AstNode => asNode(node[key], key)

export const sourceLocation = (node: AstNode): { readonly line: number; readonly column: number } => ({

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Check the node's actual shape (the error attaches the node) and use the correct key
  2. If the value is a nested node, retrieve it with getNode/asNode and read its string field instead
  3. Match parser and interpreter versions so field encodings agree
  4. Use getOptional-style access or check key existence for optional string fields

Example fix

// before
const name = getString(callNode, "callee") // callee is a node
// after
const name = getString(asNode(callNode.callee, "callee"), "name")
Defensive patterns

Strategy: type-guard

Validate before calling

const v = node[key]
if (typeof v !== "string") {
  throw new Error(`Expected string at node.${key}, got ${typeof v}`)
}
getString(node, key)

Type guard

const hasStringField = (node: AstNode, key: string): boolean => typeof node[key] === "string"

Try / catch

try {
  name = getString(node, "name")
} catch (e) {
  if (e instanceof InterpreterRuntimeError && e.message.includes("to be a string")) {
    // value may be a nested Identifier node; resolve its name instead
    name = node["name"] && typeof node["name"] === "object" ? getString(node["name"] as AstNode, "name") : null
  } else throw e
}

Prevention

When it happens

Trigger: Calling getString(node, key) where node[key] is undefined (missing/typo'd key), a number (numeric literal stored as number), or another non-string type — e.g. getString(callNode, "callee") on a node whose callee is a nested node, not a name.

Common situations: Grammar mismatch between parser and interpreter versions; expecting an identifier name where the parser stores a nested Identifier node; accessing a key absent on that node kind (e.g. reading `name` off a node type that has no name).

Related errors


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