astrid-runtime/astrid · error

legacy capsule migration exceeds the bounded principal limit

Error message

legacy capsule migration exceeds the bounded principal limit ({MAX_PRINCIPALS_PER_PASS})

What it means

Legacy capsule migration processes principals in bounded passes and hard-caps a single pass at MAX_PRINCIPALS_PER_PASS = 4096 bindings. If the principal directory contains more than 4096 aliases, the migration refuses to run rather than perform an unbounded loop that could take unbounded time or memory. This is a deliberate safety bound, not a corruption indicator.

Source

Thrown at crates/astrid-capsule-install/src/storage/migration.rs:265

            .entry(receipt.uid)
            .or_default()
            .push(receipt.capsule_id);
    }
    Ok(migrated.into_iter().collect())
}

/// Import legacy capsule directories for every admitted principal and return
/// a canonical authority-retirement proof for the barrier ledger.
pub fn migrate_all_native_capsules_with_report(
    store: &Arc<RuntimePrincipalStore>,
    home: &astrid_core::dirs::AstridHome,
    directory: &astrid_storage::PrincipalDirectory,
    workspace_targets: &[std::path::PathBuf],
) -> anyhow::Result<LegacyCapsuleMigrationReport> {
    const MAX_PRINCIPALS_PER_PASS: usize = 4096;
    let bindings = directory.bindings();
    if bindings.len() > MAX_PRINCIPALS_PER_PASS {
        bail!(
            "legacy capsule migration exceeds the bounded principal limit ({MAX_PRINCIPALS_PER_PASS})"
        );
    }
    let mut report = LegacyCapsuleMigrationReport::default();
    for (alias, _uid) in bindings {
        let principal_report =
            migrate_native_capsules_with_report(store, home, &alias, workspace_targets)?;
        report
            .retired_authorities
            .extend(principal_report.retired_authorities);
    }
    report.retired_authorities.sort();
    Ok(report)
}

/// Receipt status for one admitted principal's legacy env/secret boundary.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LegacyEnvSecretImportStatus {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Reduce the number of principals in the directory before migrating (archive or delete unused aliases).
  2. Split the principal directory into batches and migrate each batch against a directory view containing at most 4096 bindings.
  3. Raise MAX_PRINCIPALS_PER_PASS in a patched build if your workload genuinely needs larger passes (accepting longer migration runs).
  4. Contact maintainers if you need chunked migration support upstream.

Example fix

// before
migrate_all_native_capsules(&home, &directory)?; // bails with >4096 bindings

// after: prune unused bindings first
let bindings: Vec<_> = directory.bindings().into_iter().collect();
assert!(bindings.len() <= 4096, "prune principals before migrating");
migrate_all_native_capsules(&home, &directory)?;
Defensive patterns

Strategy: validation

Validate before calling

let count = directory.bindings().len();
if count > 4096 {
    return Err(anyhow::anyhow!(
        "{} principals exceed the 4096 per-pass migration limit; prune or batch first", count));
}

Type guard

fn within_pass_limit(bindings: &[(String, u64)]) -> bool {
    bindings.len() <= 4096
}

Try / catch

match migrate_all_native_capsules(&home, &directory) {
    Ok(report) => { /* ... */ }
    Err(e) if e.to_string().contains("bounded principal limit") => {
        eprintln!("too many principals: batch the migration");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling migrate_all_native_capsules or migrate_legacy_layout when directory.bindings() returns more than 4096 entries.

Common situations: Very large or long-lived legacy installs with thousands of principal aliases; directories accumulated junk aliases over years; a test or script created thousands of principals.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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