{"record":{"id":"fe41ee052bfa7c0e","repo":"different-ai/openwork","slug":"unsupported-for-in-binding","errorCode":null,"errorMessage":"Unsupported for...in binding.","messagePattern":"Unsupported for\\.\\.\\.in binding\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/interpreter/runtime.ts","lineNumber":1199,"sourceCode":"          node,\n        )\n      }\n\n      let declaration: { readonly pattern: AstNode; readonly mutable: boolean } | undefined\n      let assignmentName: string | undefined\n\n      if (left.type === \"VariableDeclaration\") {\n        const declarations = getArray(left, \"declarations\")\n        if (declarations.length !== 1) {\n          throw new InterpreterRuntimeError(\"for...in supports one declared binding.\", left)\n        }\n\n        const declarator = asNode(declarations[0], \"declarations[0]\")\n        declaration = { pattern: getNode(declarator, \"id\"), mutable: getString(left, \"kind\") !== \"const\" }\n      } else if (left.type === \"Identifier\") {\n        assignmentName = getString(left, \"name\")\n      } else {\n        throw new InterpreterRuntimeError(\"Unsupported for...in binding.\", left)\n      }\n\n      for (const key of keys) {\n        if (declaration) {\n          self.pushScope()\n          yield* self.declarePattern(declaration.pattern, key, declaration.mutable, left)\n        } else if (assignmentName) {\n          self.setIdentifierValue(assignmentName, key, left)\n        }\n\n        const result = yield* self.evaluateStatement(body).pipe(\n          Effect.ensuring(\n            Effect.sync(() => {\n              if (declaration) self.popScope()\n            }),\n          ),\n        )\n","sourceCodeStart":1181,"sourceCodeEnd":1217,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/interpreter/runtime.ts#L1181-L1217","documentation":"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.","triggerScenarios":"`for (obj.key in source)` or any for...in whose left AST node is neither VariableDeclaration nor Identifier.","commonSituations":"Generated CodeMode code that tries to write each key into an object property directly in the loop head.","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."],"exampleFix":"// before\nfor (out[key] in src) { ... }\n// after\nfor (const key in src) { out[key] = src[key]; }","handlingStrategy":"validation","validationCode":"// AST check before execution\nconst t = forInNode.left.type;\nif (t !== \"VariableDeclaration\" && t !== \"Identifier\") {\n  throw new Error(\"for...in target must be a declaration or identifier\");\n}","typeGuard":"const isValidForInLeft = (n: AstNode): boolean =>\n  n.type === \"Identifier\" ||\n  (n.type === \"VariableDeclaration\" && Array.isArray(n.declarations) && n.declarations.length === 1);","tryCatchPattern":"try {\n  interpret(src);\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.message.includes(\"Unsupported for...in binding\")) {\n    // rewrite to `for (const k in src)` with in-body assignment\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["codemode","interpreter","for-in","syntax"],"backgroundTag":"invalid-loop-binding","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}