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

  1. Swap the endpoints so the lower height comes first: `--bulk-height-range 100:200`
  2. Use `--bulk-height-range auto` to target recent heights automatically without computing bounds
  3. 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

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


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