sindresorhus/got · error · Error
Protocol "${this.protocol}" not supported. Expected "https:"
Error message
Protocol "${this.protocol}" not supported. Expected "https:" What it means
Http2ClientRequest constructor at http2-client.ts:1048 refuses any protocol other than `https:` (unless an `h2session` is being injected, which implies the caller already has a session). HTTP/2 over cleartext (h2c) is not supported for client requests in this implementation; the protocol must be `https:`.
Source
Thrown at source/core/utils/http2-client.ts:1048
}
class Http2ClientRequest extends Writable {
constructor(input: string | URL | NormalizedRequestOptions, options?: NormalizedRequestOptions | RequestCallback, callback?: RequestCallback) {
super({
autoDestroy: false,
emitClose: false,
});
const normalized = normalizeInput(input, options, callback);
this.options = normalized.options;
this.callback = normalized.callback;
this.method = (this.options.method ?? 'GET').toUpperCase();
this.path = this.method === HTTP2_METHOD_CONNECT ? String(this.options.path ?? '') : String(this.options.path ?? '/');
this.protocol = String(this.options.protocol ?? 'https:');
this.headers = Object.create(null) as RequestHeaders;
if (this.protocol !== 'https:' && !this.options.h2session) {
throw new Error(`Protocol "${this.protocol}" not supported. Expected "https:"`);
}
const headers = this.options.headers as RequestHeaders | undefined;
if (headers) {
for (const [key, value] of Object.entries(headers)) {
this.setHeader(key, value);
}
}
if (this.options.auth && !this.hasHeader('authorization')) {
this.setHeader('authorization', `Basic ${Buffer.from(this.options.auth).toString('base64')}`);
}
if (this.callback) {
this.once('response', this.callback);
}
View on GitHub (pinned to e3924aa1e5)
Solutions
- Use an `https://` URL when `http2: true` is set.
- If you must talk h2c (cleartext), use a dedicated h2c client — Got does not support it.
- Scope the `http2: true` default to https-only instances, or branch on the URL protocol before enabling http2.
- Verify `prefixUrl` / `url` literals start with `https://` when http2 is on.
Example fix
// before
await got('http://api.internal/svc', {http2: true});
// after
await got('https://api.internal/svc', {http2: true}); Defensive patterns
Strategy: validation
Validate before calling
function assertHttp2Compatible(url) {
const protocol = new URL(url).protocol;
if (protocol !== 'https:') {
throw new Error(`HTTP/2 requires https:, got ${protocol}`);
}
}
assertHttp2Compatible(url);
await got(url, {http2: true}); Type guard
const isHttpsUrl = (u: string | URL): boolean => (typeof u === 'string' ? new URL(u).protocol : u.protocol) === 'https:';
Prevention
- Scope `http2: true` defaults to https-only Got instances.
- Validate URL protocol before enabling http2 on dynamic URLs.
- Keep `prefixUrl` on `https://` when http2 is the default.
- Document that h2c (cleartext) is unsupported so callers don't try.
When it happens
Trigger: Calling `got('http://example.com', {http2: true})` (cleartext http URL with http2 enabled), passing a `URL` whose `.protocol === 'http:'` to the http2 path, or a config that sets `http2: true` globally but targets an http origin.
Common situations: Forgetting that HTTP/2 client support is TLS-only; pointing a default-`http2` instance at a plain-http internal service; misconfigured `prefixUrl` using `http://`; local dev against an http upstream while production is https.
Related errors
- HTTP/2 pseudo-headers are not supported in `options.headers`
- HTTPS option `${key}` does not exist
- The session is gracefully closing. No new streams are allowe
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/37032dc25a764d7b.json.
Report an issue: GitHub.