astrid-runtime/astrid · error

legacy env/secret status exceeds the bounded principal limit

Error message

legacy env/secret status exceeds the bounded principal limit ({MAX_PRINCIPALS_PER_PASS})

What it means

legacy_env_secret_import_status computes per-principal import status for legacy env/secret data and, like migration, bounds a single pass to MAX_PRINCIPALS_PER_PASS = 4096 bindings. If the principal directory holds more than 4096 aliases, status computation is refused instead of fanning out an unbounded number of filesystem scans. Called from import_env_and_secrets.

Source

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

    pub alias: PrincipalId,
    /// Whether the legacy per-principal env directory still has entries.
    pub native_env_present: bool,
    /// Whether the legacy per-principal secret root still has entries.
    pub native_secret_present: bool,
    /// Durable capsule scopes that do not carry a completed import receipt.
    pub unreceipted_capsules: Vec<String>,
}

/// Inspect legacy env/secret retirement completeness for every admitted UID.
pub async fn legacy_env_secret_import_status(
    store: &RuntimePrincipalStore,
    home: &astrid_core::dirs::AstridHome,
    directory: &astrid_storage::PrincipalDirectory,
) -> anyhow::Result<Vec<LegacyEnvSecretImportStatus>> {
    const MAX_PRINCIPALS_PER_PASS: usize = 4096;
    let bindings = directory.bindings();
    if bindings.len() > MAX_PRINCIPALS_PER_PASS {
        bail!(
            "legacy env/secret status exceeds the bounded principal limit ({MAX_PRINCIPALS_PER_PASS})"
        );
    }
    let mut statuses = Vec::with_capacity(bindings.len());
    for (alias, uid) in bindings {
        let principal_home = home.principal_home(&alias);
        astrid_core::platform_fs::verify_no_redirects(principal_home.root())
            .with_context(|| format!("verify legacy principal root for {alias}"))?;
        let native_env_present = legacy_entries_present(&principal_home.env_dir())?;
        let native_secret_present =
            legacy_entries_present(&home.secrets_dir().join(alias.as_str()))?;
        let owner = StateOwner::Principal(uid);
        let mut unreceipted_capsules = Vec::new();
        for summary in store.capsules().list(&owner)? {
            let scope = astrid_storage::env::principal_env_store(store.kv(), uid, summary.id())?;
            if scope
                .get(astrid_storage::env::LEGACY_IMPORT_MARKER_KEY)
                .await?

View on GitHub (pinned to affd8760f4)

Solutions

  1. Prune or archive unused principals so the directory has at most 4096 bindings.
  2. Import env/secret data in batches: split principals into groups of ≤4096 and call import per group.
  3. Patch MAX_PRINCIPALS_PER_PASS upward if your deployment legitimately exceeds the bound.

Example fix

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

// after: prune first
if directory.bindings().len() > 4096 {
    prune_unused_principals(&directory)?;
}
import_env_and_secrets(&home, &directory)?;
Defensive patterns

Strategy: validation

Validate before calling

if directory.bindings().len() > 4096 {
    eprintln!("principal directory too large for one env/secret import pass");
}

Type guard

fn importable(directory: &astrid_storage::PrincipalDirectory) -> bool {
    directory.bindings().len() <= 4096
}

Try / catch

match import_env_and_secrets(&home, &directory) {
    Ok(statuses) => { /* ... */ }
    Err(e) if e.to_string().contains("bounded principal limit") => {
        eprintln!("split principals into batches of ≤4096 and import per batch");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling import_env_and_secrets (which calls legacy_env_secret_import_status) when directory.bindings() returns more than 4096 principals.

Common situations: Bulk imports that created thousands of principals; legacy home directories shared across many projects/users; scripted mass-registration of aliases before import.

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/b9e2bc0bb53de547. Report an issue: GitHub.