astrid-runtime/astrid · error

stability fixture has no interior boundary

Error message

stability fixture has no interior boundary

What it means

`sampled_boundaries` samples boundary positions from a stability fixture at configured quantiles. It drops the last byte to build the 'interior' region; if the fixture is empty or a single byte, there is no interior boundary to sample, so the function refuses rather than returning empty/garbage results.

Source

Thrown at crates/astrid-storage-chunker-evidence/src/stability.rs:143

    let summary = summarize(&cases, neighborhoods.len())?;
    Ok(StabilityResult {
        candidate: candidate.name.clone(),
        fixture_bytes: u64::try_from(base.len())?,
        base_chunks: u64::try_from(original.len())?,
        summary,
        cases,
    })
}

fn sampled_boundaries(
    original: &[Chunk],
    quantiles_basis_points: &[u16],
) -> Result<Vec<(u16, usize)>> {
    let interior = original
        .get(..original.len().saturating_sub(1))
        .ok_or_else(|| anyhow::anyhow!("stability fixture has no interior boundary"))?;
    if interior.is_empty() {
        bail!("stability fixture has no interior boundary");
    }
    let mut sampled = Vec::with_capacity(quantiles_basis_points.len());
    let mut previous_index = None;
    for quantile in quantiles_basis_points {
        if *quantile == 0 || *quantile >= 10_000 {
            bail!("stability quantiles must lie strictly between zero and 10,000");
        }
        let index = usize::try_from(
            u64::try_from(interior.len())?
                .checked_mul(u64::from(*quantile))
                .and_then(|value| value.checked_div(10_000))
                .ok_or_else(|| anyhow::anyhow!("stability quantile overflow"))?,
        )?
        .min(
            interior
                .len()
                .checked_sub(1)
                .expect("the empty interior returned above"),

View on GitHub (pinned to affd8760f4)

Solutions

  1. Replace the fixture with content of at least 2 bytes (practically, many chunk-boundary-sized bytes).
  2. Check the fixture file/path for truncation — verify its size on disk matches expectations.
  3. Skip fixtures smaller than the minimum in the caller before invoking measure_fixture.
  4. If a tiny fixture is intentional, guard sampled_boundaries to return an empty sample instead of erroring.

Example fix

// before
let fixture: Vec<u8> = Vec::new();
// after
let fixture: Vec<u8> = (0..64 * 1024).map(|i| (i % 251) as u8).collect();
Defensive patterns

Strategy: validation

Validate before calling

fn fixture_samplable(fixture: &[u8]) -> bool {
    fixture.len() >= 2
}

Type guard

fn is_interior_samplable(original: &[u8]) -> bool {
    original.len().checked_sub(1).map(|n| n > 0).unwrap_or(false)
}

Try / catch

match measure_fixture(&fixture, &quantiles) {
    Err(e) if e.to_string().contains("no interior boundary") => {
        eprintln!("fixture too small ({} bytes); skipping", fixture.len());
    },
    r => r?,
}

Prevention

When it happens

Trigger: Calling `measure_fixture` with a fixture byte string of length 0 or 1, so `original.get(..len-1)` yields None (empty input) or an empty interior slice.

Common situations: A test/evidence fixture file defined as empty or one byte long; a fixture path resolving to a stub placeholder; configuration listing a fixture that was truncated to a single byte.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/c18c73d567d156f5. Report an issue: GitHub.