denoland/deno · error · TypeError

Unsupported 'alpnProtocols' option provided. 'h2' and…

Error message

Unsupported 'alpnProtocols' option provided. 'h2' and 'http/1.1' are automatically supported.

What it means

Deno.serve does not let callers configure ALPN: when TLS is enabled it always negotiates 'h2' and 'http/1.1' automatically (listenOpts.alpnProtocols is hardcoded to both). Passing an `alpnProtocols` option throws this TypeError at startup to make the limitation explicit rather than accepting and ignoring a custom list.

Solutions

  1. Delete the `alpnProtocols` option — h2 and http/1.1 are already enabled over TLS
  2. If you need custom ALPN, drop to Deno.listenTls plus a manual HTTP loop instead of Deno.serve
  3. For protocol-specific behavior, branch on `request.proto` (h2 vs http/1.1) inside the handler

Example fix

// before
Deno.serve({ port: 443, cert, key, alpnProtocols: ['h2'], handler });

// after
Deno.serve({ port: 443, cert, key, handler }); // h2 + http/1.1 automatic
Defensive patterns

Strategy: validation

Validate before calling

// Reject unsupported keys up front:
if ('alpnProtocols' in opts) {
  throw new Error('alpnProtocols is not configurable on Deno.serve; h2 and http/1.1 are automatic');
}
Deno.serve(opts);

Prevention

When it happens

Trigger: Adding `alpnProtocols: ['h2']` (or any value) to serve options, porting config from Deno.listenTls where alpnProtocols was configurable, or trying to restrict the server to a single protocol via options.

Common situations: Copy-paste from listenTls-based code, teams trying to disable HTTP/2 or force HTTP/3-adjacent settings, hardening checklists that list ALPN configuration.

Related errors


AI-assisted analysis of denoland/deno@abd22074e4 (2026-08-20). Data as JSON: /api/errors/6dc2e678962b8c66. Report an issue: GitHub.

Appendix: source

Thrown at ext/http/00_serve.ts:1397

      automaticCompression,
    );
  }

  const listenOpts = {
    hostname: options.hostname ?? "0.0.0.0",
    port: options.port ?? 8000,
    reusePort: options.reusePort ?? false,
    loadBalanced: options[kLoadBalanced] ?? false,
    tcpBacklog: options.tcpBacklog,
  };

  if (options.certFile || options.keyFile) {
    throw new TypeError(
      "Unsupported 'certFile' / 'keyFile' options provided: use 'cert' / 'key' instead.",
    );
  }
  if (options.alpnProtocols) {
    throw new TypeError(
      "Unsupported 'alpnProtocols' option provided. 'h2' and 'http/1.1' are automatically supported.",
    );
  }

  let listener;
  if (wantsHttps) {
    if (!options.cert || !options.key) {
      throw new TypeError(
        "Both 'cert' and 'key' must be provided to enable HTTPS",
      );
    }
    listenOpts.cert = options.cert;
    listenOpts.key = options.key;
    listenOpts.alpnProtocols = ["h2", "http/1.1"];
    listener = listenTls(listenOpts);
    listenOpts.port = listener.addr.port;
  } else {
    listener = listen(listenOpts);

View on GitHub (pinned to abd22074e4)