linera-io/linera-protocol · error
Failed to write updated server config
Error message
Failed to write updated server config
What it means
Panic when `Persist::persist(&mut server_config)` fails after `edit-shards` replaced `server_config.internal_network.shards`. Same mechanism as other persist failures: pretty JSON is written to `<path>.json.new` (0600), flushed, then atomically renamed over the config. If this fires, the old config is still on disk untouched — the shard edit simply did not land.
Source
Thrown at linera-service/src/server.rs:942
}
}
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)
.await
.expect("Failed to write updated server config");
}
}
}
fn generate_shard_configs(
num_shards: &str,
host: &str,
port: &str,
metrics_port: &Option<String>,
) -> anyhow::Result<Vec<ShardConfig>> {
let mut shards = Vec::new();
let len = num_shards.len();
let num_shards = num_shards
.parse::<NonZeroU16>()
.context("Failed to parse the number of shards")?;
let pattern = "%".repeat(len);
for i in 1u16..=num_shards.into() {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Verify writability: `touch <dir>/.probe && rm <dir>/.probe`, and check `df -h <dir>`.
- Fix ownership of the config directory and any `*.json.new` leftovers, then rerun edit-shards.
- Mount the config volume read-write.
- Propagate the error in code instead of expect to see the exact io::Error.
Example fix
// before
Persist::persist(&mut server_config)
.await
.expect("Failed to write updated server config");
// after
Persist::persist(&mut server_config)
.await
.with_context(|| format!("unable to update server config {}", server_config_path.display()))?; Defensive patterns
Strategy: validation
Validate before calling
let dir = server_config_path.parent().unwrap_or(Path::new("."));
anyhow::ensure!(!fs_err::metadata(dir)?.permissions().readonly(), "config dir is read-only: {}", dir.display());
let mut staging = server_config_path.clone();
staging.set_extension("json.new");
if staging.exists() {
fs_err::remove_file(&staging)?;
} Try / catch
if let Err(err) = Persist::persist(&mut server_config).await {
eprintln!("error: failed to write updated server config {}: {err}", server_config_path.display());
std::process::exit(1);
} Prevention
- Run edit-shards as the user that owns the server config directory.
- Check writability with a probe file and `df -h` before editing in constrained environments.
- Clean stale `server.json.new` files between attempts.
- Rerun edit-shards after fixing the environment: the atomic rename means the old config is intact and the edit can be reapplied safely.
When it happens
Trigger: Config directory read-only or unwritable by the editing user; ENOSPC while writing the staging file; leftover `server.json.new` owned by root from an earlier containerized run; rename blocked by unusual filesystem semantics.
Common situations: Editing shard configs on a deployment directory owned by root while running as another user; small tmpfs mounts in tests; CI containers with read-only layers where the config was copied in.
Related errors
- Unable to open server config file
- Unable to write server config file
- Cannot process inbox for follow-only chain {chain_id}. Use `
- failed to load contract bytecode from {contract:?}: {e}
- failed to load service bytecode from {service:?}: {e}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/a78d07ed0ae00f66.
Report an issue: GitHub.