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

  1. Check the OS error in the message: fix permissions on the temp dir (chmod/chown) so the service user can create <tmp>/lore-server.
  2. If <tmp>/lore-server exists as a file, remove or rename it so the directory can be created.
  3. Point TMPDIR at a writable location before starting the server, or configure explicit TLS settings so the ephemeral path is never used.
  4. 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

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.

Related errors


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)