{"record":{"id":"9e13741383ed0e5a","repo":"denoland/deno","slug":"if-key-is-specified-cert-must-be-specified-as","errorCode":null,"errorMessage":"If `key` is specified, `cert` must be specified as well for `${api}`","messagePattern":"If `key` is specified, `cert` must be specified as well for `(.+?)`","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/net/02_tls.js","lineNumber":153,"sourceCode":"  // 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,\n  hostname = \"0.0.0.0\",\n  transport = \"tcp\",\n  alpnProtocols = undefined,\n  reusePort = false,\n  tcpBacklog = 511,","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/net/02_tls.js#L135-L171","documentation":"The mirror-image check in loadTlsKeyPair(): providing key without cert throws this TypeError. Both halves of the key pair are mandatory whenever certificate-based TLS is configured, for clients (connectTls) and servers (listenTls) alike.","triggerScenarios":"Deno.connectTls({ key }) / Deno.listenTls({ key }) with no cert; options built from env where only TLS_KEY was set.","commonSituations":"Secrets mounted individually (key present, cert missing); refactors that moved cert into another variable; half-configured mTLS client setups.","solutions":["Provide both cert and key as PEM strings","Validate the pair at startup: if either cert or key is missing, abort with a clear configuration error","Check that both secret files/env vars resolve before constructing options"],"exampleFix":"// before\nDeno.listenTls({ port: 443, key: Deno.readTextFileSync(\"key.pem\") });\n\n// after\nconst [cert, key] = await Promise.all([\n  Deno.readTextFile(\"cert.pem\"),\n  Deno.readTextFile(\"key.pem\"),\n]);\nDeno.listenTls({ port: 443, cert, key });","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":["Symmetric secret naming (MYAPP_TLS_CERT / MYAPP_TLS_KEY) checked together","Never build TLS options through partial spreads that can drop one field","Validate the pair before constructing the options object"],"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"}