linera-io/linera-protocol · error
Unable to write committee description
Error message
Unable to write committee description
What it means
Panic when `Persist::persist(&mut config)` fails after the committee file was created in `server generate`. The CommitteeConfig is serialized as pretty JSON to `committee.json.new` and atomically renamed over the target; failure is an I/O error on staging create/write/flush/rename or, rarely, a serialization error. Because of the staging-rename design, a previously existing committee file is left untouched when this panic fires.
Source
Thrown at linera-service/src/server.rs:922
.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");
info!("Wrote committee config {}", committee.to_str().unwrap());
}
}
ServerCommand::EditShards {
server_config_path,
num_shards,
host,
port,
metrics_port,
} => {
let mut server_config =
persistent::File::<ValidatorServerConfig>::read(&server_config_path)
.expect("Failed to read server config");
let shards = generate_shard_configs(&num_shards, &host, &port, &metrics_port)
.expect("Failed to generate shard configs");
server_config.internal_network.shards = shards;
Persist::persist(&mut server_config)View on GitHub (pinned to 6c226ddcb3)
Solutions
- Free space or enlarge the volume (`df -h <dir>`).
- Make the committee directory writable by the running user (chown/chmod, rw mount).
- Remove stale `committee.json.new` files.
- Propagate the error instead of expect in custom builds to capture the exact errno.
Example fix
// before
Persist::persist(&mut config)
.await
.expect("Unable to write committee description");
// after
Persist::persist(&mut config)
.await
.with_context(|| format!("unable to write committee file {}", committee.display()))?; Defensive patterns
Strategy: validation
Validate before calling
let dir = committee.parent().unwrap_or(Path::new("."));
anyhow::ensure!(!fs_err::metadata(dir)?.permissions().readonly(), "committee dir is read-only: {}", dir.display());
let mut staging = committee.clone();
staging.set_extension("json.new");
if staging.exists() {
fs_err::remove_file(&staging)?;
} Try / catch
if let Err(err) = Persist::persist(&mut config).await {
eprintln!("error: unable to write committee description {}: {err}", committee.display());
std::process::exit(1);
} Prevention
- Check `df -h` on the config volume before generating committees on shared test machines.
- Clean `committee.json.new` leftovers between runs in scripted environments.
- Run all config-writing commands as the same user to keep 0600 staging files writable.
- Remember the previous committee file survives a failed persist (atomic rename), so a retry after fixing the environment is safe.
When it happens
Trigger: ENOSPC while flushing the staging file; EACCES/EROFS creating `committee.json.new` in a read-only or root-owned directory; rename failing on exotic filesystems; leftover staging file that the current user cannot write or replace.
Common situations: Full disks on testnet machines; config directories on read-only mounts; mixed root/non-root container runs leaving root-owned files; large validator sets filling the last bits of a small volume.
Related errors
- Unable to write server config file
- Unable to open committee configuration
- Failed to write updated server config
- {}: {error}
- failed to load contract bytecode from {contract:?}: {e}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/960ac06b726c07b5.
Report an issue: GitHub.