denoland/deno · error · TypeError
If `cert` is specified, `key` must be specified as well for
Error message
If `cert` is specified, `key` must be specified as well for `${api}` What it means
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.
Source
Thrown at ext/net/02_tls.js:148
function loadTlsKeyPair(api, {
keyFormat,
cert,
key,
}) {
// TODO(mmastrac): remove this temporary symbol when the API lands
if (arguments[1][resolverSymbol] !== undefined) {
return createTlsKeyResolver(arguments[1][resolverSymbol]);
}
// Check for "pem" format
if (keyFormat !== undefined && keyFormat !== "pem") {
throw new TypeError(
`If "keyFormat" is specified, it must be "pem": received "${keyFormat}"`,
);
}
if (cert !== undefined && key === undefined) {
throw new TypeError(
`If \`cert\` is specified, \`key\` must be specified as well for \`${api}\``,
);
}
if (cert === undefined && key !== undefined) {
throw new TypeError(
`If \`key\` is specified, \`cert\` must be specified as well for \`${api}\``,
);
}
if (cert !== undefined) {
return op_tls_key_static(cert, key);
} else {
return op_tls_key_null();
}
}
function listenTls({
port = 0,View on GitHub (pinned to 89f33cbef2)
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
Example fix
// before
Deno.listenTls({ port: 443, cert: Deno.readTextFileSync("cert.pem") });
// after
Deno.listenTls({
port: 443,
cert: Deno.readTextFileSync("cert.pem"),
key: Deno.readTextFileSync("key.pem"),
}); Defensive patterns
Strategy: validation
Validate before calling
function requireKeyPair(opts: { cert?: string; key?: string }): { cert: string; key: string } {
const { cert, key } = opts;
if ((cert !== undefined || key !== undefined) && (cert === undefined || key === undefined)) {
throw new Error("TLS options require both cert and key together");
}
return { cert: cert!, key: key! };
} Type guard
function hasCompleteKeyPair(o: { cert?: string; key?: string }): o is { cert: string; key: string } {
return (o.cert === undefined) === (o.key === undefined);
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: TLS_CERT env var set but TLS_KEY empty or misspelled; deployment secrets mounted asymmetrically; spreads that drop one field ({ ...certOnly }).
Related errors
- If `key` is specified, `cert` must be specified as well for
- If "keyFormat" is specified, it must be "pem": received "${k
- A key and certificate are required for `Deno.listenTls`
- Unsupported transport: '${transport}'
- Invalid port: '${maybePort}'
AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16).
Data as JSON: /api/errors/7c0bdf2360b383c4.
Report an issue: GitHub.