Repository: nodejs/undici (2026-04-08T15:06:55Z)

Issue:
H2CClient ignores the connect option
## Bug Description

`H2CClient` destructures `connect` from `clientOpts` but does not pass it to `Client`, so the option is ignored.

This appears to be a regression from the refactor where `H2CClient` started extending `Client` directly. As a result:

- custom `connect` functions are not used
- invalid `connect` values are not rejected
- the documented `connect` option for `H2CClient` does not match runtime behavior

## Reproducible By

```js
import { H2CClient } from 'undici'

const client = new H2CClient('http://localhost:3000', {
  connect (opts, callback) {
    console.log('CUSTOM_CONNECT_CALLED')
    callback(new Error('custom connector used'))
  }
})

client.request({ path: '/', method: 'GET' }).catch((err) => {
  console.log(err.message)
}).finally(() => {
  client.close().catch(() => {})
})
```

## Expected Behavior

`CUSTOM_CONNECT_CALLED` should be printed

## Logs & Screenshots

Nothing is printed

## Environment

* macOS 15.1 / Darwin 25.1.0 arm64
* Node.js v24.14.1
* undici 8.0.2

### Additional context

This happens as h2c destructures `connect`, but it's not passed Client
https://github.com/nodejs/undici/blob/743aa8986579dae7f2585c9e17089583787360b3/lib/dispatcher/h2c-client.js#L18-L19


Discussion:

Patch:
diff --git a/lib/dispatcher/h2c-client.js b/lib/dispatcher/h2c-client.js
index bd385225ea1..5fe7e778ba4 100644
--- a/lib/dispatcher/h2c-client.js
+++ b/lib/dispatcher/h2c-client.js
@@ -15,7 +15,7 @@ class H2CClient extends Client {
       )
     }
 
-    const { connect, maxConcurrentStreams, pipelining, ...opts } =
+    const { maxConcurrentStreams, pipelining, ...opts } =
             clientOpts ?? {}
     let defaultMaxConcurrentStreams = 100
     let defaultPipelining = 100


Test patch:
diff --git a/test/h2c-client.js b/test/h2c-client.js
index fd551a94343..193589863c4 100644
--- a/test/h2c-client.js
+++ b/test/h2c-client.js
@@ -140,6 +140,32 @@ test('Connect to h2c server over a unix domain socket', { skip: process.platform
   })
 })
 
+test('Should pass custom connect function to Client', async t => {
+  const planner = tspl(t, { plan: 3 })
+
+  const connectError = new Error('custom connect error')
+  const socketPath = '/var/run/test.sock'
+  const client = new H2CClient('http://localhost', {
+    socketPath,
+    connect (opts, cb) {
+      planner.strictEqual(opts.socketPath, socketPath)
+      planner.strictEqual(opts.allowH2, true)
+      cb(connectError, null)
+    }
+  })
+
+  t.after(() => client.close())
+
+  client.request({
+    path: '/',
+    method: 'GET'
+  }, (err) => {
+    planner.strictEqual(err, connectError)
+  })
+
+  await planner.completed
+})
+
 test('Should throw if bad useH2c has been passed', async t => {
   t = tspl(t, { plan: 1 })