{"record":{"id":"ea2df3986a4bc10a","repo":"different-ai/openwork","slug":"for-in-supports-one-declared-binding","errorCode":null,"errorMessage":"for...in supports one declared binding.","messagePattern":"for\\.\\.\\.in supports one declared binding\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/interpreter/runtime.ts","lineNumber":1191,"sourceCode":"      // namespace/tool names at that node - the same enumeration Object.keys performs.\n      // Anything else (strings, Maps, Sets, numbers, null, ...) is a deliberate error rather\n      // than real JS's surprising behavior (indices for strings, zero iterations for\n      // Maps/Sets/null): the hint points at the constructs that do what the program means.\n      const keys = self.enumerableKeys(right)\n      if (keys === undefined) {\n        throw new InterpreterRuntimeError(\n          \"for...in requires a plain object, array, or tools reference in CodeMode. Use for...of for arrays/strings/Maps/Sets, or Object.keys(value) for a key list.\",\n          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","sourceCodeStart":1173,"sourceCodeEnd":1209,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/interpreter/runtime.ts#L1173-L1209","documentation":"Like for...of, the for...in head accepts only a single declared binding. If the left side is a VariableDeclaration whose declarations array has a length other than 1, the interpreter throws at the declaration node. Multiple declarators in a for-in head are invalid in real JavaScript too; this makes it an explicit runtime error for AST-driven execution.","triggerScenarios":"A for...in AST whose VariableDeclaration `declarations` array contains zero or two-plus declarators — usually from programmatically generated ASTs.","commonSituations":"CodeMode ASTs emitted by an LLM or code generator that merged or dropped declarators; hand-built ASTs in tests.","solutions":["Emit exactly one declarator: `for (const k in obj)`.","Split extra declarations into separate statements before the loop.","Fix the AST producer (generator/transformer) to guarantee one declaration per for-in head."],"exampleFix":"// before (AST)\ndeclarations: [decl(k), decl(j)]\n// after\ndeclarations: [decl(k)]","handlingStrategy":"validation","validationCode":"// AST check before execution\nif (forInNode.left.type === \"VariableDeclaration\" && forInNode.left.declarations.length !== 1) {\n  throw new Error(\"for...in head must declare exactly one binding\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  interpret(src);\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.message.includes(\"for...in supports one\")) {\n    // emit a single declarator in the for-in head\n  }\n  throw e;\n}","preventionTips":["Emit exactly one declarator in for-in heads.","Hoist any extra declarations before the loop.","Validate generated AST loop nodes before execution."],"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"}