{"record":{"id":"7c0bdf2360b383c4","repo":"denoland/deno","slug":"if-cert-is-specified-key-must-be-specified-as","errorCode":null,"errorMessage":"If `cert` is specified, `key` must be specified as well for `${api}`","messagePattern":"If `cert` is specified, `key` must be specified as well for `(.+?)`","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/net/02_tls.js","lineNumber":148,"sourceCode":"function loadTlsKeyPair(api, {\n  keyFormat,\n  cert,\n  key,\n}) {\n  // TODO(mmastrac): remove this temporary symbol when the API lands\n  if (arguments[1][resolverSymbol] !== undefined) {\n    return createTlsKeyResolver(arguments[1][resolverSymbol]);\n  }\n\n  // Check for \"pem\" format\n  if (keyFormat !== undefined && keyFormat !== \"pem\") {\n    throw new TypeError(\n      `If \"keyFormat\" is specified, it must be \"pem\": received \"${keyFormat}\"`,\n    );\n  }\n\n  if (cert !== undefined && key === undefined) {\n    throw new TypeError(\n      `If \\`cert\\` is specified, \\`key\\` must be specified as well for \\`${api}\\``,\n    );\n  }\n  if (cert === undefined && key !== undefined) {\n    throw new TypeError(\n      `If \\`key\\` is specified, \\`cert\\` must be specified as well for \\`${api}\\``,\n    );\n  }\n\n  if (cert !== undefined) {\n    return op_tls_key_static(cert, key);\n  } else {\n    return op_tls_key_null();\n  }\n}\n\nfunction listenTls({\n  port = 0,","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/net/02_tls.js#L130-L166","documentation":"loadTlsKeyPair() requires cert and key to be supplied together: specifying cert without key throws this TypeError, naming the API ('Deno.connectTls' or 'Deno.listenTls'). A certificate alone cannot complete TLS authentication; its matching private key is mandatory.","triggerScenarios":"Deno.listenTls({ port: 443, cert }) with no key; Deno.connectTls({ cert }) for mTLS without the client key; option objects built conditionally that only set cert.","commonSituations":"TLS_CERT env var set but TLS_KEY empty or misspelled; deployment secrets mounted asymmetrically; spreads that drop one field ({ ...certOnly }).","solutions":["Provide both cert and key as PEM strings","Load them symmetrically (same env prefix / directory) and fail fast at startup if either is missing","Double-check secret names and that the key is not gated behind a separate conditional"],"exampleFix":"// before\nDeno.listenTls({ port: 443, cert: Deno.readTextFileSync(\"cert.pem\") });\n\n// after\nDeno.listenTls({\n  port: 443,\n  cert: Deno.readTextFileSync(\"cert.pem\"),\n  key: Deno.readTextFileSync(\"key.pem\"),\n});","handlingStrategy":"validation","validationCode":"function requireKeyPair(opts: { cert?: string; key?: string }): { cert: string; key: string } {\n  const { cert, key } = opts;\n  if ((cert !== undefined || key !== undefined) && (cert === undefined || key === undefined)) {\n    throw new Error(\"TLS options require both cert and key together\");\n  }\n  return { cert: cert!, key: key! };\n}","typeGuard":"function hasCompleteKeyPair(o: { cert?: string; key?: string }): o is { cert: string; key: string } {\n  return (o.cert === undefined) === (o.key === undefined);\n}","tryCatchPattern":null,"preventionTips":["Load cert and key in one place, from one config source, with a single existence check","Fail fast at startup when only one of TLS_CERT/TLS_KEY is present","Add a smoke test that starts the TLS listener in CI to catch half-configured secrets"],"tags":["tls","certificates","keys","validation","deno"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}