EpicGames/lore · error
failed to create directory
Error message
failed to create directory {} for ephemeral certificate: {e} What it means
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).
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.
Example fix
// before export TMPDIR=/readonly/tmp // after export TMPDIR=/var/tmp mkdir -p "$TMPDIR" && chmod 700 "$TMPDIR"
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust, preflight before starting the server
let dir = std::env::temp_dir().join("lore-server");
if dir.exists() && !dir.is_dir() {
return Err(format!("{} exists and is not a directory", dir.display()));
}
std::fs::create_dir_all(&dir).map_err(|e| format!("temp dir not writable: {e}"))?; Try / catch
match std::fs::create_dir_all(&dir) {
Ok(()) => {},
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
eprintln!("cannot create {}: permission denied; set TMPDIR to a writable path", dir.display());
std::process::exit(1);
}
Err(e) => return Err(anyhow::Error::new(e).context(format!("failed to create {}", dir.display()))),
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- TLS is partially configured: cert_file and pkey_file must…
- failed to write ephemeral certificate
- failed to write ephemeral private key
- [environment.endpoint] auth_url is set but [server.auth] is…
- [environment.endpoint] auth_url and [server.auth]…
AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13).
Data as JSON: /api/errors/6be6202d9d9e27fa.
Report an issue: GitHub.
Appendix: source
Thrown at lore-server/src/server.rs:1070
}
/// Build a [`CertificateSettings`](crate::tls::CertificateSettings) for an
/// endpoint that has no certificate configured by generating an ephemeral
/// self-signed certificate and writing it under the system temporary directory.
///
/// Used for QUIC endpoints that carry no mTLS requirement, so a stand alone
/// server binary with no external config can serve TLS out of the box. A
/// prominent warning is logged because these certificates are untrusted and
/// regenerated on every startup.
///
/// The file names carry the process id: several servers routinely share one
/// machine (and therefore one temporary directory), and a fixed name would let
/// them overwrite each other's certificate between the write here and the read
/// in the endpoint setup, pairing one server's certificate with another's key.
fn generate_ephemeral_certificate(endpoint: &str) -> Result<crate::tls::CertificateSettings> {
let dir = local_data_dir();
std::fs::create_dir_all(&dir).map_err(|e| {
anyhow!(
"failed to create directory {} for ephemeral certificate: {e}",
dir.display()
)
})?;
let process_id = std::process::id();
let cert_file = dir.join(format!("{endpoint}-{process_id}-cert.pem"));
let pkey_file = dir.join(format!("{endpoint}-{process_id}-key.pem"));
let generated = lore_transport::tls::generate_self_signed(vec![
"localhost".to_string(),
"127.0.0.1".to_string(),
"::1".to_string(),
])?;
std::fs::write(&cert_file, generated.cert_pem).map_err(|e| {
anyhow!(
"failed to write ephemeral certificate {}: {e}",View on GitHub (pinned to 074eb0b0d1)