{"record":{"id":"3b918da2ba8b93dc","repo":"denoland/deno","slug":"both-cert-and-key-must-be-provided-to-enable-h","errorCode":null,"errorMessage":"Both 'cert' and 'key' must be provided to enable HTTPS","messagePattern":"Both 'cert' and 'key' must be provided to enable HTTPS","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/http/00_serve.ts","lineNumber":1405,"sourceCode":"    loadBalanced: options[kLoadBalanced] ?? false,\n    tcpBacklog: options.tcpBacklog,\n  };\n\n  if (options.certFile || options.keyFile) {\n    throw new TypeError(\n      \"Unsupported 'certFile' / 'keyFile' options provided: use 'cert' / 'key' instead.\",\n    );\n  }\n  if (options.alpnProtocols) {\n    throw new TypeError(\n      \"Unsupported 'alpnProtocols' option provided. 'h2' and 'http/1.1' are automatically supported.\",\n    );\n  }\n\n  let listener;\n  if (wantsHttps) {\n    if (!options.cert || !options.key) {\n      throw new TypeError(\n        \"Both 'cert' and 'key' must be provided to enable HTTPS\",\n      );\n    }\n    listenOpts.cert = options.cert;\n    listenOpts.key = options.key;\n    listenOpts.alpnProtocols = [\"h2\", \"http/1.1\"];\n    listener = listenTls(listenOpts);\n    listenOpts.port = listener.addr.port;\n  } else {\n    listener = listen(listenOpts);\n    listenOpts.port = listener.addr.port;\n  }\n\n  const addr = listener.addr;\n\n  const onListen = (scheme) => {\n    if (options.onListen) {\n      options.onListen(addr);","sourceCodeStart":1387,"sourceCodeEnd":1423,"githubUrl":"https://github.com/denoland/deno/blob/abd22074e47c6a5cd14e9e4e84743f084aa5a575/ext/http/00_serve.ts#L1387-L1423","documentation":"When serve options request HTTPS (signaled by cert/key presence), serveInner requires both halves of the keypair: a certificate alone or a private key alone cannot build a TLS listener. This TypeError fires synchronously at startup when exactly one of `options.cert` / `options.key` is set, before any socket is bound.","triggerScenarios":"`Deno.serve({ cert })` without key, `key` present but `cert` missing, or conditionally spreading TLS options (`...(tls ?? {})`) where only one field is defined — e.g. cert loaded from an env var whose key counterpart is unset.","commonSituations":"Environment-driven TLS config where one secret is missing in a deploy environment, copy-paste from examples that only showed one field, templating bugs that drop one PEM.","solutions":["Provide both `cert` and `key` PEM strings whenever either is present","Validate before starting: `if (env.CERT || env.KEY) require both` and fail with a clear message","Gate the whole TLS block on availability of both secrets, or default to plain HTTP in dev"],"exampleFix":"// before\nDeno.serve({ port: 443, cert: pem, handler }); // key missing\n\n// after\nDeno.serve({\n  port: 443,\n  cert: await Deno.readText('./cert.pem'),\n  key: await Deno.readText('./key.pem'),\n  handler,\n});","handlingStrategy":"validation","validationCode":"// Require the keypair as a unit before starting:\nconst cert = env.TLS_CERT, key = env.TLS_KEY;\nif ((cert ?? key) !== undefined && (!cert || !key)) {\n  throw new Error('HTTPS requires both TLS_CERT and TLS_KEY');\n}\nconst opts = cert && key ? { cert, key, handler } : { handler };\nDeno.serve(opts);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat cert and key as one inseparable config unit; validate both before serve","Fail startup with a clear message when only one TLS secret is present in the environment","Default to plain HTTP in dev instead of half-configured TLS"],"tags":["http","deno-serve","tls","https","config","startup"],"backgroundTag":"incomplete-tls-config","analyzedSha":"abd22074e47c6a5cd14e9e4e84743f084aa5a575","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}