{"record":{"id":"3c1a0015ac016a70","repo":"facebook/docusaurus","slug":"https-support-require-proving-a-certificate-and-ke","errorCode":null,"errorMessage":"HTTPS support require proving a certificate and key at the same time.\\nYou only provided a ${cert ? 'certificate' : 'key'} (with ${fileProvided.source}) at path path=${fileProvided.path}.","messagePattern":"HTTPS support require proving a certificate and key at the same time\\.\\\\nYou only provided a (.+?) \\(with (.+?)\\) at path path=(.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/docusaurus/src/webpack/utils/getHttpsConfig.ts","lineNumber":152,"sourceCode":"      'env DOCUSAURUS_SSL_KEY_FILE',\n    );\n  }\n  if (process.env.SSL_KEY_FILE) {\n    return readCryptoFile(\n      path.resolve(cwd, process.env.SSL_KEY_FILE),\n      'env SSL_KEY_FILE',\n    );\n  }\n  return null;\n}\n\nfunction ensureCertKeyBothProvided(\n  cert: CryptoFile | null,\n  key: CryptoFile | null,\n) {\n  if ((cert || key) && !(cert && key)) {\n    const fileProvided = (cert ?? key)!;\n    throw new Error(\n      logger.interpolate`HTTPS support require proving a certificate and key at the same time.\nYou only provided a ${cert ? 'certificate' : 'key'} (with ${fileProvided.source}) at path path=${fileProvided.path}.`,\n    );\n  }\n}\n\n// Get the https config\n// Return cert files if provided via CLI or env, otherwise just true or false.\n// CLI options take precedence over env vars.\nexport default async function getHttpsConfig(\n  options: Partial<HttpsConfigOptions> = {},\n): Promise<boolean | {cert: Buffer; key: Buffer}> {\n  const cwd = await fs.realpath(process.cwd());\n\n  const [cert, key] = await Promise.all([\n    getCert(options, cwd),\n    getKeyFile(options, cwd),\n  ]);","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/facebook/docusaurus/blob/3f483e80e326cc646b54b83d564b3f0c4881b9a6/packages/docusaurus/src/webpack/utils/getHttpsConfig.ts#L134-L170","documentation":"Thrown by ensureCertKeyBothProvided() when exactly one of {cert, key} is resolved (an XOR: `(cert || key) && !(cert && key)`). Docusaurus requires both a certificate and a private key together for HTTPS. The message reports which one you supplied and through which {source} (CLI arg or env var) and at which path, so you can supply the missing counterpart. Cert/key are resolved independently from options.sslCert / DOCUSAURUS_SSL_CRT_FILE / SSL_CRT_FILE and options.sslKey / DOCUSAURUS_SSL_KEY_FILE / SSL_KEY_FILE respectively.","triggerScenarios":"Setting only DOCUSAURUS_SSL_CRT_FILE without a matching DOCUSAURUS_SSL_KEY_FILE (or vice versa); passing --ssl-cert but forgetting --ssl-key; having a stale SSL_CRT_FILE env var from another project while only providing the key explicitly now.","commonSituations":"Copy-pasting half of an HTTPS setup from docs; env vars leaking from a shell profile (export SSL_CRT_FILE=...) so the cert is silently picked up even though you only intended to set the key; switching from one machine to another where only one of the two env vars is exported.","solutions":["Read the {source}/{path} in the message: it tells you whether you provided a cert or a key, and via CLI arg or env var.","Supply the missing counterpart through the same channel (both via CLI flags, or both via env vars) — e.g. add `--ssl-key ./key.pem` alongside `--ssl-cert ./cert.pem`.","Unset stale env vars from the other half so only an explicit, intentional pair remains: `unset SSL_CRT_FILE` if you now pass certs on the CLI.","Confirm both files exist and are readable (or you will then hit error 160/161)."],"exampleFix":"// before\nDOCUSAURUS_SSL_CRT_FILE=./cert.pem docusaurus start --https\n// after\nDOCUSAURUS_SSL_CRT_FILE=./cert.pem DOCUSAURUS_SSL_KEY_FILE=./key.pem docusaurus start --https","handlingStrategy":"validation","validationCode":"function validateHttpsCertKeyPair(opts: {\n  sslCert?: string; sslKey?: string;\n  env = process.env;\n}) {\n  const certSrc = opts.sslCert ?? opts.env.DOCUSAURUS_SSL_CRT_FILE ?? opts.env.SSL_CRT_FILE;\n  const keySrc = opts.sslKey ?? opts.env.DOCUSAURUS_SSL_KEY_FILE ?? opts.env.SSL_KEY_FILE;\n  if ((certSrc || keySrc) && !(certSrc && keySrc)) {\n    throw new Error(\n      `HTTPS needs BOTH cert and key. Got cert=${certSrc ?? '(none)'}, key=${keySrc ?? '(none)'}.`,\n    );\n  }\n}\n\n// call before getHttpsConfig(): validateHttpsCertKeyPair({ sslCert, sslKey });","typeGuard":"const hasBothCertAndKey = (o: {sslCert?: string; sslKey?: string}, env = process.env) =>\n  Boolean((o.sslCert ?? env.DOCUSAURUS_SSL_CRT_FILE ?? env.SSL_CRT_FILE) &&\n         (o.sslKey ?? env.DOCUSAURUS_SSL_KEY_FILE ?? env.SSL_KEY_FILE));","tryCatchPattern":null,"preventionTips":["Always set cert and key through the same channel (both CLI flags or both env vars).","Run `env | grep -i ssl` to spot stale env vars leaking from shell profiles.","Keep a single npm script that passes both flags together, so contributors never set just one."],"tags":["https","ssl","config","dev-server"],"backgroundTag":null,"analyzedSha":"3f483e80e326cc646b54b83d564b3f0c4881b9a6","analyzedAt":"2026-08-12T13:25:04.382Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}