linera-io/linera-protocol · error
Unable to write server config file
Error message
Unable to write server config file
What it means
Panic when `Persist::persist(&mut server)` fails while writing a validator server config created by `server generate`. `File::persist` serializes the value to pretty JSON into a staging file `<path>.json.new` (mode 0600), flushes it, then atomically renames it over `<path>`; the staging file is removed on serialization or write errors. Failure means the staging file could not be opened/written, serialization failed, or the final rename failed.
Source
Thrown at linera-service/src/server.rs:904
ServerCommand::Generate {
validators,
committee,
testing_prng_seed,
} => {
let mut config_validators = Vec::new();
let mut rng = Box::<dyn CryptoRng>::from(testing_prng_seed);
for options_path in validators {
let options_string = fs_err::tokio::read_to_string(options_path)
.await
.expect("Unable to read validator options file");
let options: ValidatorOptions = toml::from_str(&options_string)
.unwrap_or_else(|_| panic!("Invalid options file format: \n {options_string}"));
let path = options.server_config_path.clone();
let mut server = make_server_config(&path, &mut rng, options)
.expect("Unable to open server config file");
Persist::persist(&mut server)
.await
.expect("Unable to write server config file");
info!("Wrote server config {}", path.to_str().unwrap());
println!(
"{},{}",
server.validator.public_key, server.validator.account_key
);
config_validators.push(Persist::into_value(server).validator);
}
if let Some(committee) = committee {
let mut config = persistent::File::new(
&committee,
CommitteeConfig {
validators: config_validators,
},
)
.expect("Unable to open committee configuration");
Persist::persist(&mut config)
.await
.expect("Unable to write committee description");View on GitHub (pinned to 6c226ddcb3)
Solutions
- Check writability and space: `df -h <dir>` and `touch <dir>/.probe` (then remove the probe).
- Remount the volume read-write, or move the config path to a writable directory.
- Free disk space or enlarge the volume if the failure is ENOSPC.
- Remove stale root-owned `<path>.json.new` leftovers before rerunning.
- Replace `.expect` with `.with_context(...)?` in embedded code to surface the underlying io::Error.
Example fix
// before
Persist::persist(&mut server)
.await
.expect("Unable to write server config file");
// after
Persist::persist(&mut server)
.await
.with_context(|| format!("unable to write server config {}", path.display()))?; Defensive patterns
Strategy: validation
Validate before calling
let dir = path.parent().unwrap_or(Path::new("."));
anyhow::ensure!(!fs_err::metadata(dir)?.permissions().readonly(), "config dir is read-only: {}", dir.display());
let staging = {
let mut p = path.clone();
p.set_extension("json.new");
p
};
if staging.exists() {
fs_err::remove_file(&staging)?;
} Try / catch
if let Err(err) = Persist::persist(&mut server).await {
eprintln!("error: unable to write server config {}: {err}", path.display());
std::process::exit(1);
} Prevention
- Mount config volumes read-write and monitor disk usage where validator configs live.
- Always run generate as the same (non-root) user so 0600 files and staging leftovers stay owned by it.
- Avoid NFS/FUSE for the config path; the write path relies on same-directory atomic rename.
- Treat `.json.new` files found during provisioning as crash residue and clean them.
When it happens
Trigger: Config directory not writable or on a read-only mount so `open("<path>.json.new")` fails with EACCES/EROFS; disk full (ENOSPC) while flushing the staging file; leftover `.json.new` owned by another user; rename failing on exotic filesystems (NFS/FUSE); JSON serialization of ValidatorServerConfig failing after an internal schema change.
Common situations: Kubernetes pod with the config path on a read-only ConfigMap mount; small disks on CI or test VMs; Docker image run once as root then as non-root, leaving a root-owned staging file; network volumes where same-directory rename semantics differ.
Related errors
- Unable to write committee description
- Failed to write updated server config
- Unable to open server config file
- Unable to open committee configuration
- Failed to open log file for writing
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/7ed948d4e27b60eb.
Report an issue: GitHub.