{"record":{"id":"a78d07ed0ae00f66","repo":"linera-io/linera-protocol","slug":"failed-to-write-updated-server-config","errorCode":null,"errorMessage":"Failed to write updated server config","messagePattern":"Failed to write updated server config","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-service/src/server.rs","lineNumber":942,"sourceCode":"            }\n        }\n\n        ServerCommand::EditShards {\n            server_config_path,\n            num_shards,\n            host,\n            port,\n            metrics_port,\n        } => {\n            let mut server_config =\n                persistent::File::<ValidatorServerConfig>::read(&server_config_path)\n                    .expect(\"Failed to read server config\");\n            let shards = generate_shard_configs(&num_shards, &host, &port, &metrics_port)\n                .expect(\"Failed to generate shard configs\");\n            server_config.internal_network.shards = shards;\n            Persist::persist(&mut server_config)\n                .await\n                .expect(\"Failed to write updated server config\");\n        }\n    }\n}\n\nfn generate_shard_configs(\n    num_shards: &str,\n    host: &str,\n    port: &str,\n    metrics_port: &Option<String>,\n) -> anyhow::Result<Vec<ShardConfig>> {\n    let mut shards = Vec::new();\n    let len = num_shards.len();\n    let num_shards = num_shards\n        .parse::<NonZeroU16>()\n        .context(\"Failed to parse the number of shards\")?;\n    let pattern = \"%\".repeat(len);\n\n    for i in 1u16..=num_shards.into() {","sourceCodeStart":924,"sourceCodeEnd":960,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-service/src/server.rs#L924-L960","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nPersist::persist(&mut server_config)\n    .await\n    .expect(\"Failed to write updated server config\");\n// after\nPersist::persist(&mut server_config)\n    .await\n    .with_context(|| format!(\"unable to update server config {}\", server_config_path.display()))?;","handlingStrategy":"validation","validationCode":"let dir = server_config_path.parent().unwrap_or(Path::new(\".\"));\nanyhow::ensure!(!fs_err::metadata(dir)?.permissions().readonly(), \"config dir is read-only: {}\", dir.display());\nlet mut staging = server_config_path.clone();\nstaging.set_extension(\"json.new\");\nif staging.exists() {\n    fs_err::remove_file(&staging)?;\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = Persist::persist(&mut server_config).await {\n    eprintln!(\"error: failed to write updated server config {}: {err}\", server_config_path.display());\n    std::process::exit(1);\n}","preventionTips":["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."],"tags":["rust","file-io","atomic-write","permissions","cli"],"backgroundTag":"file-write-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}