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
- Use an http:// origin URL for H2CClient.
- If you actually need HTTP/2 over TLS, use the regular Client with allowH2: true instead of H2CClient.
- Normalize the URL before construction: strip or rewrite the scheme to http: when h2c is intended.
- 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
- Keep h2c origins in a dedicated config section so they are visually distinct from TLS endpoints.
- If TLS is needed, switch to Client with allowH2 rather than H2CClient.
- Normalize URLs once at config-load time and fail fast on the wrong scheme.
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
- Proxy URL must use socks5:// or socks:// protocol
- UND_ERR_INVALID_ARG
- Query params cannot be passed when url already contains "?"
- UND_ERR_INVALID_ARG
- UND_ERR_REQ_CONTENT_LENGTH_MISMATCH
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/b91a84d85a501a0e.
Report an issue: GitHub.