Skip to content

DispatchOptions.upgrade accepts boolean in types but runtime rejects it #5466

Description

@MicroMilo

Summary

DispatchOptions.upgrade currently accepts boolean in the public TypeScript type, but the runtime request validator rejects any truthy non-string value with InvalidArgumentError: upgrade must be a string. A TypeScript-valid call such as client.dispatch({ path: '/', method: 'GET', upgrade: true }, handler) therefore fails before any connector/network dispatch.

Code path

Producer / validator / feedback anchors:

  • types/dispatcher.d.ts:116-117: upgrade?: boolean | string | null;
  • lib/core/request.js:134-136: truthy upgrade values are rejected unless typeof upgrade === 'string'.
  • lib/dispatcher/dispatcher-base.js:172-180: the validator failure is surfaced through handler.onResponseError(null, err) and dispatch() returns false when the handler has an error hook.

Steps to reproduce

Validation level: dynamic reproduction plus source-control-flow validation.

const { Client } = require('undici')

const client = new Client('http://127.0.0.1:9', {
  connect () {
    throw new Error('connector should not be reached when option validation fails')
  },
})

const handler = {
  onRequestStart () {},
  onResponseStart () {},
  onResponseData () {},
  onResponseEnd () {},
  onResponseError (_controller, err) {
    console.log(`handler.error.name=${err.name}`)
    console.log(`handler.error.message=${err.message}`)
  },
}

console.log(client.dispatch({ path: '/', method: 'GET', upgrade: true }, handler))

Observed output from the local repro:

handler.error.name=InvalidArgumentError
handler.error.message=upgrade must be a string
dispatch_return=false

Expected behavior

The public type and runtime validator should agree on the upgrade option contract. Either boolean should be rejected by TypeScript, or true should be normalized to a well-defined upgrade token.

Actual behavior

The TypeScript surface permits upgrade: true, but runtime rejects it before dispatch and reports upgrade must be a string.

Existing coverage

I searched current open/closed issues and PRs for upgrade must be a string, DispatchOptions upgrade boolean, and related types/dispatcher.d.ts upgrade terms. I did not find exact coverage. Nearby upgrade/WebSocket issues and PRs appear to cover protocol behavior, not this type/runtime option drift.

Suggested fix

The lower-risk fix is to narrow DispatchOptions.upgrade to string | null, matching the current runtime validator. If boolean support is intended, the runtime should define and test what true means.

Suggested tests

  • Add a type-level negative assertion for upgrade: true on DispatchOptions if narrowing the type.
  • Keep or add a runtime test that upgrade: 'websocket' remains accepted.
  • Keep invalid non-string runtime values flowing to onResponseError.

Submitted with Codex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions