linera-io/linera-protocol · error
--bulk-height-range must be `auto` or `FROM:TO`
Error message
--bulk-height-range must be `auto` or `FROM:TO`
What it means
The --bulk-height-range value was neither the literal "auto" nor a FROM:TO pair, because no ':' separator was found. resolve_range accepts exactly "auto" (computed as a window below the chain tip) or two u64 numbers split on the first colon.
Source
Thrown at linera-service/src/cli/validator_benchmark/bulk_download.rs:175
bytes_in,
certs_received,
duration_secs: duration,
mb_per_sec: (bytes_in as f64 / 1_048_576.0) / duration,
certs_per_sec: certs_received as f64 / duration,
latency_ms: samples.summary(),
}
}
/// Resolve the height range: `auto` targets the most recent
/// `batch_size * AUTO_BATCH_COUNT` heights up to the tip; otherwise `FROM:TO`.
fn resolve_range(arg: &str, tip: u64, batch_size: u32) -> Result<(u64, u64)> {
if arg == "auto" {
let span = batch_size as u64 * AUTO_BATCH_COUNT;
Ok((tip.saturating_sub(span), tip))
} else {
let (a, b) = arg
.split_once(':')
.ok_or_else(|| anyhow::anyhow!("--bulk-height-range must be `auto` or `FROM:TO`"))?;
let from: u64 = a.trim().parse()?;
let to: u64 = b.trim().parse()?;
if to < from {
anyhow::bail!("--bulk-height-range FROM must not exceed TO");
}
Ok((from, to))
}
}
#[cfg(test)]
mod tests {
use super::resolve_range;
#[test]
fn auto_under_tip() {
assert_eq!(
resolve_range("auto", 50_000, 100).unwrap(),
(40_000, 50_000)View on GitHub (pinned to 6c226ddcb3)
Solutions
- Use the literal `--bulk-height-range auto` to let the tool derive the window from the tip.
- Or spell the explicit range with a colon: `--bulk-height-range 1000:2000`.
- Ensure FROM <= TO and both are plain decimal u64 values (no units, no 0x).
- Check for stray whitespace or a duplicated flag overriding the value.
Example fix
# before --bulk-height-range 1000-2000 # after --bulk-height-range 1000:2000 # or: --bulk-height-range auto
Defensive patterns
Strategy: type-guard
Validate before calling
fn is_valid_bulk_height_range(s: &str) -> bool {
if s == "auto" { return true; }
match s.split_once(':') {
Some((a, b)) => {
let (a, b) = (a.trim().parse::<u64>(), b.trim().parse::<u64>());
matches!((a, b), (Ok(from), Ok(to)) if from <= to)
}
None => false,
}
} Type guard
fn is_valid_bulk_height_range(s: &str) -> bool {
s == "auto" || s.split_once(':').is_some_and(|(a, b)| {
a.trim().parse::<u64>().is_ok() && b.trim().parse::<u64>().is_ok()
})
} Prevention
- Use the colon separator, not a dash.
- Prefer `auto` unless a fixed window is required.
- Validate the argument in wrapper scripts before launching the benchmark.
When it happens
Trigger: Passing "100-200" (dash instead of colon), a bare number "1500", or "auto " with trailing characters that defeat the literal comparison.
Common situations: Muscle memory from other tools that use dash ranges; scripts templating the argument with a wrong separator; also note the follow-up guards: FROM must not exceed TO, and both ends must parse as u64.
Related errors
- Validator spec must be in format: public_key,account_key,add
- --output specified but resolved to no entries
- unknown output format `{other}` (expected json|yaml|md|brief
- expected query to start with 'query', got: {s}
- expected whitespace after 'query' keyword
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/00581bce12ba1648.
Report an issue: GitHub.