{"record":{"id":"6be6202d9d9e27fa","repo":"EpicGames/lore","slug":"failed-to-create-directory-for-ephemeral-certificate-e","errorCode":null,"errorMessage":"failed to create directory {} for ephemeral certificate: {e}","messagePattern":"failed to create directory (.+?) for ephemeral certificate: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lore-server/src/server.rs","lineNumber":1070,"sourceCode":"}\n\n/// Build a [`CertificateSettings`](crate::tls::CertificateSettings) for an\n/// endpoint that has no certificate configured by generating an ephemeral\n/// self-signed certificate and writing it under the system temporary directory.\n///\n/// Used for QUIC endpoints that carry no mTLS requirement, so a stand alone\n/// server binary with no external config can serve TLS out of the box. A\n/// prominent warning is logged because these certificates are untrusted and\n/// regenerated on every startup.\n///\n/// The file names carry the process id: several servers routinely share one\n/// machine (and therefore one temporary directory), and a fixed name would let\n/// them overwrite each other's certificate between the write here and the read\n/// in the endpoint setup, pairing one server's certificate with another's key.\nfn generate_ephemeral_certificate(endpoint: &str) -> Result<crate::tls::CertificateSettings> {\n    let dir = local_data_dir();\n    std::fs::create_dir_all(&dir).map_err(|e| {\n        anyhow!(\n            \"failed to create directory {} for ephemeral certificate: {e}\",\n            dir.display()\n        )\n    })?;\n\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}\",","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/EpicGames/lore/blob/074eb0b0d1194c997d7cf28b55519e3e197b3e23/lore-server/src/server.rs#L1052-L1088","documentation":"generate_ephemeral_certificate writes a self-signed TLS certificate for the Quinn endpoint into local_data_dir() (= std::env::temp_dir().join(\"lore-server\")) when no explicit TLS config exists. Before writing, it calls std::fs::create_dir_all(&dir) and maps any IO failure to this anyhow error including the directory path and the OS error. Common causes are permission problems on the temp directory or a path collision (e.g. a file named lore-server in temp).","triggerScenarios":"launch_quinn_server requests an ephemeral certificate and std::fs::create_dir_all on <tmp>/lore-server fails — unwritable TMPDIR, read-only filesystem, or temp_dir()/lore-server exists as a regular file so create_dir_all cannot make it a directory.","commonSituations":"Container running as non-root with a read-only or foreign-owned /tmp; hardened systemd service with PrivateTmp and restricted write paths; TMPDIR pointing somewhere the service user cannot create directories; leftover file occupying the lore-server name.","solutions":["Check the OS error in the message: fix permissions on the temp dir (chmod/chown) so the service user can create <tmp>/lore-server.","If <tmp>/lore-server exists as a file, remove or rename it so the directory can be created.","Point TMPDIR at a writable location before starting the server, or configure explicit TLS settings so the ephemeral path is never used.","In containers/systemd, mount a writable volume at the temp location or set ReadWritePaths accordingly."],"exampleFix":"// before\nexport TMPDIR=/readonly/tmp\n\n// after\nexport TMPDIR=/var/tmp\nmkdir -p \"$TMPDIR\" && chmod 700 \"$TMPDIR\"","handlingStrategy":"try-catch","validationCode":"// Rust, preflight before starting the server\nlet dir = std::env::temp_dir().join(\"lore-server\");\nif dir.exists() && !dir.is_dir() {\n    return Err(format!(\"{} exists and is not a directory\", dir.display()));\n}\nstd::fs::create_dir_all(&dir).map_err(|e| format!(\"temp dir not writable: {e}\"))?;","typeGuard":null,"tryCatchPattern":"match std::fs::create_dir_all(&dir) {\n    Ok(()) => {},\n    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {\n        eprintln!(\"cannot create {}: permission denied; set TMPDIR to a writable path\", dir.display());\n        std::process::exit(1);\n    }\n    Err(e) => return Err(anyhow::Error::new(e).context(format!(\"failed to create {}\", dir.display()))),\n}","preventionTips":["Ensure the service user owns or can write to TMPDIR (or mount a writable volume in containers).","Confirm <tmp>/lore-server is not occupied by a regular file left from an earlier run.","For systemd, set ReadWritePaths/StateDirectory to cover the temp path; for containers, avoid read-only /tmp.","Configure explicit TLS certificates in production to skip the ephemeral path."],"tags":["filesystem","tls","startup","permissions"],"backgroundTag":"mkdir-permission-denied","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"}