{"record":{"id":"07b8e2ccb43d904e","repo":"EpicGames/lore","slug":"failed-to-write-ephemeral-private-key-e","errorCode":null,"errorMessage":"failed to write ephemeral private key {}: {e}","messagePattern":"failed to write ephemeral private key (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lore-server/src/server.rs","lineNumber":1093,"sourceCode":"\n    let process_id = std::process::id();\n    let cert_file = dir.join(format!(\"{endpoint}-{process_id}-cert.pem\"));\n    let pkey_file = dir.join(format!(\"{endpoint}-{process_id}-key.pem\"));\n\n    let generated = lore_transport::tls::generate_self_signed(vec![\n        \"localhost\".to_string(),\n        \"127.0.0.1\".to_string(),\n        \"::1\".to_string(),\n    ])?;\n\n    std::fs::write(&cert_file, generated.cert_pem).map_err(|e| {\n        anyhow!(\n            \"failed to write ephemeral certificate {}: {e}\",\n            cert_file.display()\n        )\n    })?;\n    std::fs::write(&pkey_file, generated.key_pem).map_err(|e| {\n        anyhow!(\n            \"failed to write ephemeral private key {}: {e}\",\n            pkey_file.display()\n        )\n    })?;\n\n    warn!(\n        endpoint,\n        cert = %cert_file.display(),\n        key = %pkey_file.display(),\n        \"No TLS certificate configured for the '{endpoint}' QUIC endpoint; generated an \\\n         EPHEMERAL SELF-SIGNED certificate. This is untrusted, regenerated on every restart, \\\n         and intended for local development only. Configure a real certificate for production.\"\n    );\n\n    Ok(crate::tls::CertificateSettings {\n        cert_chain: None,\n        cert_file,\n        pkey_file,","sourceCodeStart":1075,"sourceCodeEnd":1111,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/server.rs#L1075-L1111","documentation":"Immediately after writing the ephemeral certificate, generate_ephemeral_certificate writes the PEM private key (generated.key_pem) to the key file next to it; an IO failure there is mapped to this error with the key file path and OS error. Startup aborts because the quinn endpoint setup needs both files. Note a partial-write risk: the certificate may already be on disk while the key write fails, leaving mismatched/stale artifacts for the next run.","triggerScenarios":"std::fs::write(&pkey_file, generated.key_pem) fails — disk full mid-sequence, key file path occupied by a directory, ownership mismatch on the pre-existing key file, or security policy blocking the write after the cert write succeeded.","commonSituations":"Small /tmp quota consumed by the just-written cert; another server instance (or a previous root run) owning the key file; race between multiple lore-server instances sharing the same temp dir and trying to write the same key file name.","solutions":["Fix the underlying IO error: free space, correct ownership/permissions on <tmp>/lore-server and the key file.","Delete stale cert+key pairs in <tmp>/lore-server so both files are rewritten consistently by the same process.","Avoid running multiple server instances against one machine temp dir simultaneously, or give each a distinct TMPDIR.","Configure real TLS certificates to stop relying on the ephemeral mechanism."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Rust, preflight: ensure both target paths are writable and not directories\nfor f in [&cert_file, &pkey_file] {\n    if f.exists() && f.is_dir() {\n        return Err(format!(\"{} is a directory\", f.display()));\n    }\n}\n// verify space for both files\nlet free = fs4::available_space(&dir)?;\nif free < 16_384 { return Err(\"insufficient space for ephemeral key material\".into()); }","typeGuard":null,"tryCatchPattern":"let write_pair = || -> anyhow::Result<()> {\n    std::fs::write(&cert_file, &generated.cert_pem).context(\"cert write\")?;\n    std::fs::write(&pkey_file, &generated.key_pem).context(\"key write\")?;\n    Ok(())\n};\nif let Err(e) = write_pair() {\n    // clean up so no mismatched cert/key pair is left behind\n    let _ = std::fs::remove_file(&cert_file);\n    let _ = std::fs::remove_file(&pkey_file);\n    return Err(e);\n}","preventionTips":["Write cert+key atomically (to temp names, then rename) or remove both on partial failure to avoid stale mismatched pairs.","Keep enough free space in TMPDIR for both PEM files; the key write fails after the cert consumed quota.","Fix ownership of any pre-existing key file before restarting as a different user.","Run a single server instance per machine temp directory or isolate instances with distinct TMPDIRs."],"tags":["filesystem","tls","private-key","write-failed"],"backgroundTag":"file-write-failed","analyzedSha":"074eb0b0d1194c997d7cf28b55519e3e197b3e23","analyzedAt":"2026-09-13T09:00:57.509Z","contentChangedAt":"2026-09-13T09:00:57.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}