EpicGames/lore · error
failed to write ephemeral private key
Error message
failed to write ephemeral private key {}: {e} What it means
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.
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.
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust, preflight: ensure both target paths are writable and not directories
for f in [&cert_file, &pkey_file] {
if f.exists() && f.is_dir() {
return Err(format!("{} is a directory", f.display()));
}
}
// verify space for both files
let free = fs4::available_space(&dir)?;
if free < 16_384 { return Err("insufficient space for ephemeral key material".into()); } Try / catch
let write_pair = || -> anyhow::Result<()> {
std::fs::write(&cert_file, &generated.cert_pem).context("cert write")?;
std::fs::write(&pkey_file, &generated.key_pem).context("key write")?;
Ok(())
};
if let Err(e) = write_pair() {
// clean up so no mismatched cert/key pair is left behind
let _ = std::fs::remove_file(&cert_file);
let _ = std::fs::remove_file(&pkey_file);
return Err(e);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- failed to write ephemeral certificate
- failed to create directory
- gRPC internal TLS is partially configured: cert=
- TLS is partially configured: cert_file and pkey_file must…
- Maintenance TLS is partially configured: cert_file and…
AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13).
Data as JSON: /api/errors/07b8e2ccb43d904e.
Report an issue: GitHub.
Appendix: source
Thrown at lore-server/src/server.rs:1093
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}",
cert_file.display()
)
})?;
std::fs::write(&pkey_file, generated.key_pem).map_err(|e| {
anyhow!(
"failed to write ephemeral private key {}: {e}",
pkey_file.display()
)
})?;
warn!(
endpoint,
cert = %cert_file.display(),
key = %pkey_file.display(),
"No TLS certificate configured for the '{endpoint}' QUIC endpoint; generated an \
EPHEMERAL SELF-SIGNED certificate. This is untrusted, regenerated on every restart, \
and intended for local development only. Configure a real certificate for production."
);
Ok(crate::tls::CertificateSettings {
cert_chain: None,
cert_file,
pkey_file,View on GitHub (pinned to 074eb0b0d1)