nodejs/node · error · InvalidArgumentError

UND_ERR_INVALID_ARG

UND_ERR_INVALID_ARG

Error message

h2c-client: Only h2c protocol is supported

What it means

Thrown by the H2CClient constructor when the resolved origin URL protocol is not 'http:'. H2C is HTTP/2 over cleartext (RFC 8324) and is only defined for unencrypted HTTP origins; passing an https URL, or any non-http protocol, has no valid h2c semantics so the constructor rejects it.

Source

Thrown at deps/undici/src/lib/dispatcher/h2c-client.js:13

'use strict'

const { InvalidArgumentError } = require('../core/errors')
const Client = require('./client')

class H2CClient extends Client {
  constructor (origin, clientOpts) {
    if (typeof origin === 'string') {
      origin = new URL(origin)
    }

    if (origin.protocol !== 'http:') {
      throw new InvalidArgumentError(
        'h2c-client: Only h2c protocol is supported'
      )
    }

    const { maxConcurrentStreams, pipelining, ...opts } =
            clientOpts ?? {}
    const defaultMaxConcurrentStreams = maxConcurrentStreams ?? 100
    let defaultPipelining = 100

    if (
      maxConcurrentStreams != null &&
            (!Number.isInteger(maxConcurrentStreams) ||
            maxConcurrentStreams < 1)
    ) {
      throw new InvalidArgumentError('maxConcurrentStreams must be a positive integer, greater than 0')
    }

    if (pipelining != null && Number.isInteger(pipelining) && pipelining > 0) {

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Use an http:// origin URL for H2CClient.
  2. If you actually need HTTP/2 over TLS, use the regular Client with allowH2: true instead of H2CClient.
  3. Normalize the URL before construction: strip or rewrite the scheme to http: when h2c is intended.
  4. Validate the protocol in your config loader so misconfigured env vars fail early with a clear message.

Example fix

// before
new H2CClient('https://internal-svc:8080')
// after
new H2CClient('http://internal-svc:8080')
Defensive patterns

Strategy: validation

Validate before calling

const u = typeof origin === 'string' ? new URL(origin) : origin
if (u.protocol !== 'http:') {
  throw new Error(`H2CClient requires an http:// origin, got ${u.protocol}`)
}
new H2CClient(u)

Type guard

function isH2cOrigin(origin) {
  const u = typeof origin === 'string' ? new URL(origin) : origin
  return u instanceof URL && u.protocol === 'http:'
}

Prevention

When it happens

Trigger: Constructing new H2CClient('https://example.com') or new H2CClient(new URL('ftp://...')) or omitting the scheme so URL parsing yields an unexpected protocol. The string is coerced to a URL via new URL(origin) before the protocol check, so malformed inputs that still parse with a wrong scheme also hit this.

Common situations: Copy-pasting an HTTPS endpoint into an h2c config; environment variable pointing at a TLS endpoint; upgrading a plain Client to H2CClient without changing the origin scheme; mixing up h2 (TLS HTTP/2) and h2c (cleartext HTTP/2).

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/b91a84d85a501a0e. Report an issue: GitHub.