{"record":{"id":"0e06cdfc8662ee30","repo":"different-ai/openwork","slug":"for-of-requires-an-array-string-map-or-set-va","errorCode":null,"errorMessage":"for...of requires an array, string, Map, or Set value in CodeMode.","messagePattern":"for\\.\\.\\.of requires an array, string, Map, or Set value in CodeMode\\.","errorType":"exception","errorClass":"InterpreterRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/interpreter/runtime.ts","lineNumber":1089,"sourceCode":"    }).pipe(Effect.ensuring(Effect.sync(() => self.popScope())))\n  }\n\n  private evaluateForOfStatement(node: AstNode): Effect.Effect<StatementResult, unknown, R> {\n    if (getBoolean(node, \"await\")) {\n      throw new InterpreterRuntimeError(\"for await...of is not supported.\", node)\n    }\n\n    const self = this\n    return Effect.gen(function* () {\n      const left = getNode(node, \"left\")\n      const right = yield* self.evaluateExpression(getNode(node, \"right\"))\n      const body = getNode(node, \"body\")\n\n      // Arrays iterate in place; strings iterate code points; Maps iterate [key, value]\n      // pairs and Sets iterate values over a snapshot (mutation during iteration is safe).\n      const iterable = Array.isArray(right) ? right : spreadItems(right)\n      if (iterable === undefined) {\n        throw new InterpreterRuntimeError(\"for...of requires an array, string, Map, or Set value in CodeMode.\", node)\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...of 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...of binding.\", left)\n      }","sourceCodeStart":1071,"sourceCodeEnd":1107,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/interpreter/runtime.ts#L1071-L1107","documentation":"for...of in CodeMode only works over arrays, strings, Maps, and Sets (iterating over a snapshot). The right-hand expression is normalized via spreadItems; if that returns undefined the value is not one of these iterable data types and the interpreter throws. This deliberately excludes arbitrary iterables (generators, custom iterators, arguments) and non-iterables.","triggerScenarios":"`for (const x of value)` where value is a number, null/undefined, a plain object, a generator, or any custom iterable — spreadItems yields undefined for these.","commonSituations":"Iterating object properties with for...of instead of for...in/Object.entries; assuming generator functions work in CodeMode; iterating a Map-like plain object.","solutions":["Convert the value to an array first: `Object.entries(obj)`, `Object.keys(obj)`, or `Array.from(...)`.","For Maps/Sets confirm the value actually is a Map or Set instance, not a plain object shaped like one.","Materialize generator output into an array before looping (generators are unsupported)."],"exampleFix":"// before\nfor (const [k, v] of obj) { ... }\n// after\nfor (const [k, v] of Object.entries(obj)) { ... }","handlingStrategy":"type-guard","validationCode":"// ensure the loop target is CodeMode-iterable before running\nconst iterableKind = (v: unknown) =>\n  Array.isArray(v) ? \"array\" : typeof v === \"string\" ? \"string\" :\n  v instanceof Map ? \"map\" : v instanceof Set ? \"set\" : null;","typeGuard":"const isCodeModeIterable = (v: unknown): v is unknown[] | string | Map<unknown, unknown> | Set<unknown> =>\n  Array.isArray(v) || typeof v === \"string\" || v instanceof Map || v instanceof Set;","tryCatchPattern":"try {\n  interpret(src);\n} catch (e) {\n  if (e instanceof InterpreterRuntimeError && e.message.includes(\"for...of requires\")) {\n    // convert target via Object.entries/keys or Array.from\n  }\n  throw e;\n}","preventionTips":["for...of over arrays, strings, Maps, Sets only.","Use Object.entries(obj) to iterate plain objects.","Materialize generators into arrays before looping."],"tags":["codemode","interpreter","for-of","iterable"],"backgroundTag":"value-not-iterable","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}