different-ai/openwork · error · InterpreterRuntimeError
Unsupported for...in binding.
Error message
Unsupported for...in binding.
What it means
The for...in left side must be a single VariableDeclaration or a plain Identifier. Any other node kind on the left (member expressions such as `obj.k`, unsupported pattern nodes) throws this error at the left node. Assignment targets inside loop heads are limited to these two forms by the interpreter.
Source
Thrown at packages/codemode/src/interpreter/runtime.ts:1199
node,
)
}
let declaration: { readonly pattern: AstNode; readonly mutable: boolean } | undefined
let assignmentName: string | undefined
if (left.type === "VariableDeclaration") {
const declarations = getArray(left, "declarations")
if (declarations.length !== 1) {
throw new InterpreterRuntimeError("for...in supports one declared binding.", left)
}
const declarator = asNode(declarations[0], "declarations[0]")
declaration = { pattern: getNode(declarator, "id"), mutable: getString(left, "kind") !== "const" }
} else if (left.type === "Identifier") {
assignmentName = getString(left, "name")
} else {
throw new InterpreterRuntimeError("Unsupported for...in binding.", left)
}
for (const key of keys) {
if (declaration) {
self.pushScope()
yield* self.declarePattern(declaration.pattern, key, declaration.mutable, left)
} else if (assignmentName) {
self.setIdentifierValue(assignmentName, key, left)
}
const result = yield* self.evaluateStatement(body).pipe(
Effect.ensuring(
Effect.sync(() => {
if (declaration) self.popScope()
}),
),
)
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Declare `for (const k in src)` and assign to the member inside the body: `target[k] = ...`.
- Use a pre-declared plain identifier as the loop variable.
- Fix the AST generator to only emit Identifier or single-declarator VariableDeclaration left sides.
Example fix
// before
for (out[key] in src) { ... }
// after
for (const key in src) { out[key] = src[key]; } Defensive patterns
Strategy: validation
Validate before calling
// AST check before execution
const t = forInNode.left.type;
if (t !== "VariableDeclaration" && t !== "Identifier") {
throw new Error("for...in target must be a declaration or identifier");
} Type guard
const isValidForInLeft = (n: AstNode): boolean => n.type === "Identifier" || (n.type === "VariableDeclaration" && Array.isArray(n.declarations) && n.declarations.length === 1);
Try / catch
try {
interpret(src);
} catch (e) {
if (e instanceof InterpreterRuntimeError && e.message.includes("Unsupported for...in binding")) {
// rewrite to `for (const k in src)` with in-body assignment
}
throw e;
} Prevention
- Keep for-in heads to `const k` or an existing identifier.
- Do member assignment inside the loop body.
- Add AST linting for loop-head node kinds in generators.
When it happens
Trigger: `for (obj.key in source)` or any for...in whose left AST node is neither VariableDeclaration nor Identifier.
Common situations: Generated CodeMode code that tries to write each key into an object property directly in the loop head.
Related errors
- for...in supports one declared binding.
- for...of supports one declared binding.
- Unsupported for...of binding.
- for...in requires a plain object, array, or tools reference
- Expected '${key}' to be a boolean.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/fe41ee052bfa7c0e.
Report an issue: GitHub.