astrid-runtime/astrid · error

target KiB must be a power of two in 8..=256

Error message

target KiB must be a power of two in 8..=256

What it means

`candidates(target_kib)` validates that the requested chunk target is a power of two between 8 and 256 KiB inclusive before computing derived sizes. Passing anything else (e.g. 10, 0, 512) fails this validation and the function bails immediately.

Solutions

  1. Clamp/normalize the requested target to the nearest power of two within 8..=256 before calling.
  2. Validate user/config-supplied target sizes at config load time.
  3. Use one of the supported sizes: 8, 16, 32, 64, 128, or 256 KiB.

Example fix

// before
let cands = candidates(100)?;
// after
let target_kib = 100u32.next_power_of_two().clamp(8, 256); // 128
let cands = candidates(target_kib)?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_target_kib(kib: u32) -> bool {
    (8..=256).contains(&kib) && kib.is_power_of_two()
}
assert!(valid_target_kib(target_kib), "target KiB must be a power of two in 8..=256");

Try / catch

match candidates(target_kib) {
    Ok(cands) => cands,
    Err(e) => { log::warn!("invalid target {target_kib}: {e}"); candidates(default_target_kib)? }
}

Prevention

When it happens

Trigger: Calling the public `candidates(target_kib)` with a value outside 8..=256 or not a power of two (e.g. `candidates(10)`, `candidates(4)`, `candidates(512)`).

Common situations: Hand-tuned chunk sizes from config not constrained to powers of two; unit tests probing boundary values; a caller forwarding user-supplied target sizes 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 astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/873be93c6ab3b6ae. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-storage-chunker-evidence/src/algorithm.rs:148

                        visit(segment.dedup_key())?;
                    }
                }
            },
        }
        Ok(())
    }

    fn fastcdc_target_bytes(&self) -> Result<u32> {
        match self.parameters {
            Parameters::FastCdc2020 { target_bytes, .. } => Ok(target_bytes),
            _ => bail!("FastCDC candidate has non-FastCDC parameters"),
        }
    }
}

pub fn candidates(target_kib: u32) -> Result<Vec<Candidate>> {
    if !(8..=256).contains(&target_kib) || !target_kib.is_power_of_two() {
        bail!("target KiB must be a power of two in 8..=256");
    }
    let target = target_kib
        .checked_mul(1024)
        .ok_or_else(|| anyhow::anyhow!("target byte size overflow"))?;

    let fast_minimum = target / 4;
    let fast_maximum = target
        .checked_mul(4)
        .ok_or_else(|| anyhow::anyhow!("FastCDC maximum overflow"))?;
    let narrow_minimum = checked_ratio(target, 3, 4, "narrow MinCDC minimum")?;
    let narrow_maximum = checked_ratio(target, 5, 4, "narrow MinCDC maximum")?;
    let wide_minimum = target / 2;
    let wide_maximum = checked_ratio(target, 3, 2, "wide MinCDC maximum")?;
    let empirical_compromise_minimum = target / 2;
    let empirical_compromise_maximum =
        checked_ratio(target, 5, 2, "empirical-compromise MinCDC maximum")?;
    let empirical_compromise_kib = target_kib
        .checked_mul(3)

View on GitHub (pinned to affd8760f4)