{"record":{"id":"dc90ec2ec378ab8b","repo":"denoland/deno","slug":"err-invalid-state-dc90ec","errorCode":"ERR_INVALID_STATE","errorMessage":"Invalid state: The iterator method must return an object","messagePattern":"Invalid state: The iterator method must return an object","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/webstreams/util.js","lineNumber":249,"sourceCode":"      if (method == null) {\n        const syncMethod = obj[SymbolIterator];\n        if (syncMethod === undefined) {\n          throw new ERR_ARG_NOT_ITERABLE(obj);\n        }\n        return createAsyncFromSyncIterator(\n          getIterator(obj, \"sync\", syncMethod),\n        );\n      }\n    } else {\n      method = obj[SymbolIterator];\n    }\n  }\n  if (method === undefined) {\n    throw new ERR_ARG_NOT_ITERABLE(obj);\n  }\n  const iterator = FunctionPrototypeCall(method, obj);\n  if (typeof iterator !== \"object\" || iterator === null) {\n    throw new ERR_INVALID_STATE(\"The iterator method must return an object\");\n  }\n  return { iterator, nextMethod: iterator.next, done: false };\n}\n\nfunction iteratorNext(iteratorRecord, value) {\n  const result = value === undefined\n    ? FunctionPrototypeCall(iteratorRecord.nextMethod, iteratorRecord.iterator)\n    : FunctionPrototypeCall(\n      iteratorRecord.nextMethod,\n      iteratorRecord.iterator,\n      value,\n    );\n  if (typeof result !== \"object\" || result === null) {\n    throw new ERR_INVALID_STATE(\n      \"The iterator.next() method must return an object\",\n    );\n  }\n  return result;","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/webstreams/util.js#L231-L267","documentation":"After getIterator() locates an iterator method, the WHATWG protocol requires calling it to return an iterator OBJECT. If obj[Symbol.iterator]() (or the async equivalent) returns a primitive (number, string, boolean) or null, Deno's node:stream/web machinery throws ERR_INVALID_STATE ('The iterator method must return an object') rather than proceeding.","triggerScenarios":"A custom iterable whose [Symbol.iterator] returns a raw value: { [Symbol.iterator]: () => 42 }; an implementation returning this.value where value is a primitive; test mocks stubbing Symbol.iterator with () => null; a factory method that forgot 'return this' / 'return generator()'.","commonSituations":"Hand-rolled iterable protocol implementations; mocking libraries replacing Symbol.iterator with trivial stubs; refactoring an iterable class and dropping the iterator-returning statement.","solutions":["Make the iterator method return an object — the simplest fix is delegating to a generator: [Symbol.iterator]() { return this.values(); } where values is a generator","Or return the object itself with a next() method: [Symbol.iterator]() { let i = 0; const self = this; return { next: () => ({ value: self.items[i], done: i++ >= self.items.length }) }; }","Smoke-test custom iterables with [...obj] or Array.from(obj) before feeding them to streams"],"exampleFix":"// before\nconst seq = { [Symbol.iterator]: () => this.items }; // returns an array in wrong `this` context or a primitive\n\n// after\nconst seq = { *[Symbol.iterator]() { yield* this.items; } };","handlingStrategy":"validation","validationCode":"const iterFn = (source as any)?.[Symbol.iterator];\nif (typeof iterFn !== 'function') throw new TypeError('not iterable');\nconst iter = iterFn.call(source);\nif (typeof iter !== 'object' || iter === null) {\n  throw new TypeError('Symbol.iterator must return an iterator object');\n}\nReadableStream.from(source);","typeGuard":"function iteratorMethodIsSound(source: unknown): boolean {\n  const fn = (source as any)?.[Symbol.iterator];\n  if (typeof fn !== 'function') return false;\n  const it = fn.call(source);\n  return it != null && typeof it === 'object';\n}","tryCatchPattern":"try {\n  rs = ReadableStream.from(source);\n} catch (e: any) {\n  if (e?.code === 'ERR_INVALID_STATE' && /iterator method/.test(e.message)) {\n    rs = ReadableStream.from([...makeIterable(source)]); // rebuild via generator\n  } else throw e;\n}","preventionTips":["Implement Symbol.iterator by delegating to a generator — never return a primitive or this.someField","Unit-test custom iterables with [...obj] before passing them to stream APIs","Never stub Symbol.iterator with () => null in mocks"],"tags":["web-streams","iterator-protocol","validation","invalid-state"],"backgroundTag":"iterator-protocol-violation","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}