{"record":{"id":"2ac16aeebcc9f016","repo":"nodejs/node","slug":"und-err-invalid-arg-2ac16a","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-upgrade.js","lineNumber":13,"sourceCode":"'use strict'\n\nconst { InvalidArgumentError, SocketError } = require('../core/errors')\nconst { AsyncResource } = require('node:async_hooks')\nconst assert = require('node:assert')\nconst util = require('../core/util')\nconst { kHTTP2Stream } = require('../core/symbols')\nconst { addSignal, removeSignal } = require('./abort-signal')\n\nclass UpgradeHandler extends AsyncResource {\n  constructor (opts, callback) {\n    if (!opts || typeof opts !== 'object') {\n      throw new InvalidArgumentError('invalid opts')\n    }\n\n    if (typeof callback !== 'function') {\n      throw new InvalidArgumentError('invalid callback')\n    }\n\n    const { signal, opaque, responseHeaders } = opts\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    super('UNDICI_UPGRADE')\n\n    this.responseHeaders = responseHeaders || null\n    this.opaque = opaque || null\n    this.callback = callback\n    this.abort = null","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/deps/undici/src/lib/api/api-upgrade.js#L1-L31","documentation":"Thrown by undici's UpgradeHandler constructor (the upgrade() / client.upgrade() API) when the first argument opts is falsy or not an object. upgrade() requires an options object describing the target host/path to tunnel to; it does not accept a bare URL string.","triggerScenarios":"Calling client.upgrade('host:443') or client.upgrade(null); passing a URL object without wrapping it in an options bag.","commonSituations":"Assuming upgrade() shares request()'s string-URL overload; destructuring that produced undefined; migrating from http.request upgrade code that used a string.","solutions":["Pass an options object: client.upgrade({ host, port, path, headers }).","Build opts from a URL: const u = new URL(target); client.upgrade({ host: u.hostname, port: u.port, path: u.pathname }).","Ensure the options bag is never conditionally undefined."],"exampleFix":"// before\nclient.upgrade('example.com:443')\n\n// after\nclient.upgrade({ host: 'example.com', port: 443, path: '/' })","handlingStrategy":"validation","validationCode":"function upgradeOpts(urlOrOpts) {\n  if (urlOrOpts instanceof URL) return { host: urlOrOpts.hostname, port: urlOrOpts.port, path: urlOrOpts.pathname }\n  if (urlOrOpts && typeof urlOrOpts === 'object') return urlOrOpts\n  throw new TypeError('upgrade opts must be an object')\n}\n// client.upgrade(upgradeOpts(target), cb)","typeGuard":"function isUpgradeOpts(v) { return !!v && typeof v === 'object' && !Array.isArray(v) }","tryCatchPattern":null,"preventionTips":["upgrade() takes an options object, not a URL string — unlike request().","Build opts from a URL via new URL() and read hostname/port/path.","Ensure the opts bag is never undefined from conditional construction."],"tags":["undici","upgrade","validation","argument","websocket"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}