{"record":{"id":"77cbc188d87c33c6","repo":"denoland/deno","slug":"err-arg-not-iterable","errorCode":"ERR_ARG_NOT_ITERABLE","errorMessage":"${obj} must be iterable","messagePattern":"(.+?) must be iterable","errorType":"error_code","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/webstreams/util.js","lineNumber":234,"sourceCode":"    [SymbolAsyncIterator]() {\n      return this;\n    },\n  };\n  return {\n    iterator: asyncIterator,\n    nextMethod: asyncIterator.next,\n    done: false,\n  };\n}\n\nfunction getIterator(obj, kind = \"sync\", method) {\n  if (method === undefined) {\n    if (kind === \"async\") {\n      method = obj[SymbolAsyncIterator];\n      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}","sourceCodeStart":216,"sourceCodeEnd":252,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/webstreams/util.js#L216-L252","documentation":"Raised by getIterator(obj, 'async') in ext/node/polyfills/internal/webstreams/util.js, the iteration helper behind node:stream/web consumption of iterables (e.g. ReadableStream.from(source)). For async iteration it first looks up Symbol.asyncIterator; if that is null/undefined it falls back to Symbol.iterator (wrapped as async-from-sync). An object exposing NEITHER symbol is not iterable and throws ERR_ARG_NOT_ITERABLE with the inspected value in the message.","triggerScenarios":"ReadableStream.from(42), ReadableStream.from({}), or ReadableStream.from(null) via node:stream/web; a factory that accepts 'stream or iterable or value' and a raw value (number, boolean, plain object) slips through; JSON-parsed data assumed to be an iterable list.","commonSituations":"API boundaries where the argument type is loose (config loaders, job queues); passing a parsed single record instead of the records array; async pipeline code copied from samples that assumed an array.","solutions":["Pass an actual iterable: Array, String, generator, async generator, or a (web) stream","Wrap single values: ReadableStream.from([value])","Guard the boundary: check typeof obj?.[Symbol.iterator] === 'function' || typeof obj?.[Symbol.asyncIterator] === 'function' before calling"],"exampleFix":"// before\nconst rs = ReadableStream.from(source); // source may be a number/plain object\n\n// after\nconst isIterable = (v) => v != null &&\n  (typeof v[Symbol.iterator] === 'function' ||\n   typeof v[Symbol.asyncIterator] === 'function');\nconst rs = ReadableStream.from(isIterable(source) ? source : [source]);","handlingStrategy":"type-guard","validationCode":"const isAsyncIterable = (v: unknown) =>\n  v != null && typeof (v as any)[Symbol.asyncIterator] === 'function';\nconst isIterable = (v: unknown) =>\n  v != null && typeof (v as any)[Symbol.iterator] === 'function';\nconst src = isAsyncIterable(source) || isIterable(source) ? source : [source];\nconst rs = ReadableStream.from(src);","typeGuard":"function isIterableOrAsyncIterable(\n  v: unknown,\n): v is Iterable<unknown> | AsyncIterable<unknown> {\n  return v != null &&\n    (typeof (v as any)[Symbol.iterator] === 'function' ||\n      typeof (v as any)[Symbol.asyncIterator] === 'function');\n}","tryCatchPattern":"try {\n  rs = ReadableStream.from(source);\n} catch (e: any) {\n  if (e?.code === 'ERR_ARG_NOT_ITERABLE') rs = ReadableStream.from([source]);\n  else throw e;\n}","preventionTips":["Guard loose 'value | iterable' API boundaries with an isIterable check","Wrap single records in an array before passing them where a sequence is expected","Prefer generators at producer boundaries — they always satisfy the iterable protocol"],"tags":["web-streams","iterable","iterator-protocol","validation"],"backgroundTag":"not-iterable","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}