linera-io/linera-protocol · warning · anyhow
--bulk-height-range FROM must not exceed TO
Error message
--bulk-height-range FROM must not exceed TO
What it means
`resolve_range` parses the `--bulk-height-range FROM:TO` argument for the validator benchmark's bulk-download layer. Both endpoints are parsed as u64 and the run bails when TO is numerically smaller than FROM, i.e. the block-height window is inverted. The alternative form `auto` targets the most recent `batch_size * AUTO_BATCH_COUNT` heights up to the tip and never hits this check.
Source
Thrown at linera-service/src/cli/validator_benchmark/bulk_download.rs:179
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)
);
}
#[test]View on GitHub (pinned to 6c226ddcb3)
Solutions
- Swap the endpoints so the lower height comes first: `--bulk-height-range 100:200`
- Use `--bulk-height-range auto` to target recent heights automatically without computing bounds
- In scripts, sort the two heights (or validate `from <= to`) before composing the flag
Example fix
# before linera validator benchmark <addr> --chain <id> --bulk-height-range 200:100 # after linera validator benchmark <addr> --chain <id> --bulk-height-range 100:200
Defensive patterns
Strategy: validation
Validate before calling
// Validate/normalize before passing the flag.
fn normalize_range(from: u64, to: u64) -> anyhow::Result<(u64, u64)> {
if from > to {
Ok((to, from)) // or reject: bail!("inverted height range {from}:{to}")
} else {
Ok((from, to))
}
}
let (from, to) = normalize_range(from_height, to_height)?;
let flag = format!("--bulk-height-range {from}:{to}"); Prevention
- Prefer `--bulk-height-range auto` unless you need a specific window
- In scripts, derive FROM/TO from a single tip value (tip - n, tip) so they cannot be swapped
- Remember the format is FROM:TO with FROM inclusive and lower-or-equal
When it happens
Trigger: Passing an inverted explicit range such as `--bulk-height-range 200:100` (from=200, to=100) to the validator benchmark's bulk download.
Common situations: Assuming the pair is (newest:oldest) or (to:from); scripts computing the range around the chain tip and swapping the bounds on short chains; copy-paste from height-output where the newest height is printed first.
Related errors
- please specify one of `--faucet` or `--genesis`.
- preflight failed for {}: {:?}
- L2 partial sync: local sync failed ({category})
- cannot have both a json string and file
- Benchmark requires the 'opentelemetry' feature to be enabled
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/ee9607f93c9d1d3d.
Report an issue: GitHub.