nautechsystems/nautilus_trader · error

`batch_size` must be greater than zero

Error message

`batch_size` must be greater than zero

What it means

read_bulk_batched fetches Redis keys in batches of batch_size using MGET-style reads. A batch size of zero would loop forever or produce empty batches, so the function validates the argument up front and bails. This is a defensive parameter check on a public API.

Source

Thrown at crates/infrastructure/src/redis/queries.rs:210

        Ok(bytes_results)
    }

    /// Bulk reads multiple keys from Redis using MGET, batched into chunks.
    ///
    /// Keys are batched into chunks of `batch_size` to avoid exceeding Redis
    /// request size limits on some providers.
    ///
    /// # Errors
    ///
    /// Returns an error if `batch_size` is zero or if the underlying Redis MGET operation fails.
    pub async fn read_bulk_batched(
        con: &ConnectionManager,
        keys: &[String],
        batch_size: usize,
    ) -> anyhow::Result<Vec<Option<Bytes>>> {
        if batch_size == 0 {
            anyhow::bail!("`batch_size` must be greater than zero");
        }

        if keys.is_empty() {
            return Ok(vec![]);
        }

        let mut all_results: Vec<Option<Bytes>> = Vec::with_capacity(keys.len());

        for chunk in keys.chunks(batch_size) {
            let mut con = con.clone();

            let results: Vec<Option<Vec<u8>>> =
                redis::cmd("MGET").arg(chunk).query_async(&mut con).await?;

            all_results.extend(results.into_iter().map(|opt| opt.map(Bytes::from)));
        }

        Ok(all_results)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass a batch_size >= 1, e.g. saturate at the call site with batch_size.max(1).
  2. Validate/normalize the batch-size config value at startup before calling this function.
  3. Guard derived values: if batch size is computed, clamp it to a sensible minimum (e.g. 100).
  4. Note the empty-keys early return already returns Ok(vec![]) — only pass keys when non-empty and pair with a positive batch size.

Example fix

// before
let values = read_bulk_batched(&con, &keys, config.batch_size).await?;
// after
let batch = config.batch_size.max(1);
let values = read_bulk_batched(&con, &keys, batch).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: clamp batch size before calling
let batch_size = config.batch_size.unwrap_or(256).max(1);
assert!(batch_size > 0, "batch_size must be positive");

Type guard

fn positive_batch_size(n: usize) -> Option<usize> {
    if n == 0 { None } else { Some(n) }
}

Try / catch

match read_bulk_batched(&con, &keys, batch_size).await {
    Ok(values) => { /* use values */ }
    Err(e) if e.to_string().contains("batch_size") => {
        // retry once with a safe default
        read_bulk_batched(&con, &keys, 256).await
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling read_bulk_batched with batch_size == 0 — e.g. a computed batch size from an empty/default config value, or a caller deriving batch size from a slice length that happens to be zero.

Common situations: Configuration where a batch-size setting defaults to 0 or is parsed from an empty string; math like keys.len() / divisor yielding 0; passing through a user-supplied value without validation.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/e0a80d48d0f2c04f. Report an issue: GitHub.