linera-io/linera-protocol · error

Failed to generate shard configs

Error message

Failed to generate shard configs

What it means

Panic when `generate_shard_configs(&num_shards, &host, &port, &metrics_port)` returns an error in `server edit-shards`. The helper parses `num_shards` as a NonZeroU16, builds a `%` pattern as wide as the num_shards string, and for each shard index substitutes the pattern once into host/port/metrics_port before parsing the ports as u16. The real causes are the inner contexts: 'Failed to parse the number of shards', 'Failed to decode port into an integers', or the metrics-port variant; the panic text is only the outer wrapper.

Source

Thrown at linera-service/src/server.rs:938

                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)
                .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>()

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Pass a positive integer for num_shards, e.g. `4` (not 0, not empty, at most 65535).
  2. Make sure each substituted port value is an integer in 0..=65535, and that the `%` pattern width equals the number of digits in num_shards (num_shards `12` needs `%%` patterns yielding 01..12).
  3. Quote the --host/--port/--metrics-port arguments in shell so `%` and digits reach the CLI intact.
  4. Pre-validate the arguments in a wrapper script before invoking edit-shards.

Example fix

// before
let shards = generate_shard_configs(&num_shards, &host, &port, &metrics_port)
    .expect("Failed to generate shard configs");
// after
let shards = generate_shard_configs(&num_shards, &host, &port, &metrics_port)
    .with_context(|| format!("invalid shard spec: num_shards={num_shards} host={host} port={port}"))?;
Defensive patterns

Strategy: type-guard

Validate before calling

let n = num_shards.parse::<NonZeroU16>().context("num_shards must be a non-zero integer <= 65535")?;
let pattern = "%".repeat(num_shards.len());
for i in 1..=u16::from(n) {
    let index = format!("{i:0width$}", width = num_shards.len());
    port.replacen(&pattern, &index, 1).parse::<u16>()
        .with_context(|| format!("port for shard {index} is not a valid u16"))?;
    if let Some(mp) = metrics_port.as_ref() {
        mp.replacen(&pattern, &index, 1).parse::<u16>()
            .with_context(|| format!("metrics_port for shard {index} is not a valid u16"))?;
    }
}

Type guard

fn valid_shard_specs(num_shards: &str, port: &str, metrics_port: Option<&str>) -> bool {
    let Ok(n) = num_shards.parse::<NonZeroU16>() else { return false };
    let pattern = "%".repeat(num_shards.len());
    (1..=u16::from(n)).all(|i| {
        let index = format!("{i:0width$}", width = num_shards.len());
        port.replacen(&pattern, &index, 1).parse::<u16>().is_ok()
            && metrics_port
                .map_or(true, |p| p.replacen(&pattern, &index, 1).parse::<u16>().is_ok())
    })
}

Try / catch

let shards = match generate_shard_configs(&num_shards, &host, &port, &metrics_port) {
    Ok(shards) => shards,
    Err(err) => {
        eprintln!("error: failed to generate shard configs: {err:#}");
        std::process::exit(1);
    }
};

Prevention

When it happens

Trigger: num_shards given as 0, empty, non-numeric, or above 65535; a port string whose substituted value does not parse as u16 (letters left in the string, or a value above 65535); `--metrics-port` with an unparseable substituted value; a `%` pattern whose width does not match the num_shards digit count so substitution leaves stray `%` characters in the port.

Common situations: Shell mangling of unquoted `%` arguments; copy-pasted CLI templates where the pattern width no longer matches num_shards; configs migrated from scripts that used a different shard-numbering convention.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/6158cda6705b18e5. Report an issue: GitHub.