{"record":{"id":"e003bead39ef0328","repo":"nodejs/node","slug":"und-err-invalid-arg-e003be","errorCode":"UND_ERR_INVALID_ARG","errorMessage":"invalid opts","messagePattern":"invalid opts","errorType":"validation","errorClass":"InvalidArgumentError","httpStatus":null,"severity":"error","filePath":"deps/undici/src/lib/api/api-stream.js","lineNumber":62,"sourceCode":"\n  const onError = (err) => finish(err, true)\n  const onFinish = () => finish()\n\n  stream.on('close', onClose)\n  stream.on('error', onError)\n  stream.on('finish', onFinish)\n\n  if (stream.closed) {\n    process.nextTick(onClose)\n  } else if (stream.writableFinished) {\n    process.nextTick(onFinish)\n  }\n}\n\nclass StreamHandler extends AsyncResource {\n  constructor (opts, factory, callback) {\n    if (!opts || typeof opts !== 'object') {\n      throw new InvalidArgumentError('invalid opts')\n    }\n\n    const { signal, method, opaque, body, onInfo, responseHeaders } = opts\n\n    try {\n      if (typeof callback !== 'function') {\n        throw new InvalidArgumentError('invalid callback')\n      }\n\n      if (typeof factory !== 'function') {\n        throw new InvalidArgumentError('invalid factory')\n      }\n\n      if (signal && typeof signal.on !== 'function' && typeof signal.addEventListener !== 'function') {\n        throw new InvalidArgumentError('signal must be an EventEmitter or EventTarget')\n      }\n\n      if (method === 'CONNECT') {","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/api/api-stream.js#L44-L80","documentation":"Thrown by undici's StreamHandler constructor (the stream() API) when the first argument opts is falsy or not an object. stream() requires an options object describing the request (method, path, headers, factory, etc.) — passing null, undefined, a string URL, or a primitive is rejected.","triggerScenarios":"Calling undici.stream(url, factory, callback) positional style when the API expects stream({...opts}, factory, callback); passing only a URL string; passing undefined because the opts bag was conditionally built and came back empty.","commonSituations":"Confusing stream()'s signature with request()'s (which accepts a URL string as first arg); destructuring options into undefined; refactoring that split URL and options incorrectly.","solutions":["Pass a plain options object as the first argument: stream({ method, path, headers, origin }, factory, callback).","If you have a URL, merge it in: stream({ ...new URL(u), ...opts }, factory, callback).","Default the bag to at least {} only if you intentionally want defaults, but prefer constructing it explicitly."],"exampleFix":"// before\nundici.stream(targetUrl, factory, cb) // URL string is not an object\n\n// after\nundici.stream({ ...new URL(targetUrl), method: 'GET' }, factory, cb)","handlingStrategy":"validation","validationCode":"function streamOpts(urlOrOpts, extra = {}) {\n  const base = typeof urlOrOpts === 'string' || urlOrOpts instanceof URL\n    ? { ...new URL(urlOrOpts) }\n    : urlOrOpts\n  if (!base || typeof base !== 'object') throw new TypeError('stream opts must be an object')\n  return { ...base, ...extra }\n}\n// stream(streamOpts(url), factory, cb)","typeGuard":"function isStreamOpts(v) { return !!v && typeof v === 'object' && !Array.isArray(v) }","tryCatchPattern":null,"preventionTips":["Remember stream()'s signature is (optsObject, factory, callback) — no string-URL overload.","Build the opts bag explicitly; avoid passing possibly-undefined conditionals.","Wrap with a helper that normalizes URL vs object input."],"tags":["undici","stream","validation","argument"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}