astrid-runtime/astrid · critical · anyhow::Error

Failed to bind boot policy

Error message

Failed to bind boot policy: {error}

What it means

Immediately after loading the admitted-home config, the daemon calls `kernel.bind_boot_local_egress(...)` to install the capsule local egress security policy. If binding fails (the kernel rejects the policy), this error wraps the kernel's message. Boot cannot proceed because local egress policy must be bound before any capsule loads.

Solutions

  1. Read the wrapped kernel error to see which egress rule was rejected.
  2. Correct the `security.capsule_local_egress` section of the config (valid CIDRs/entries).
  3. Restart the daemon after fixing the policy so binding happens on a clean boot.

Example fix

// before (config security section)
capsule_local_egress = { allow = ["not-a-cidr"] }
// after
capsule_local_egress = { allow = ["127.0.0.0/8"] }
Defensive patterns

Strategy: validation

Validate before calling

// shell
# verify egress rules are syntactically valid CIDRs before boot
for cidr in $EGRESS_ALLOW; do
  python3 -c "import ipaddress,sys; ipaddress.ip_network(sys.argv[1])" "$cidr" || exit 1
done

Try / catch

// rust
if let Err(e) = daemon::run(args).await {
    eprintln!("{e:#}"); // kernel message names the rejected egress rule
    std::process::exit(1);
}

Prevention

When it happens

Trigger: Daemon `run()` where `security.capsule_local_egress` from the loaded config is invalid or inconsistent with kernel state, causing `bind_boot_local_egress` to return Err.

Common situations: Misconfigured egress rules (bad CIDRs, unknown allow/deny entries) in the security section of the config; policy edited after the kernel was booted with a conflicting state.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — 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/336560c9b1b09bd0. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-daemon/src/lib.rs:278

        runtime_limits,
        std::collections::HashMap::new(),
        http_limits,
        workspace_layout,
    )
    .await
    .map_err(|e| anyhow::anyhow!("Failed to boot Kernel: {e}"))?;

    // Local egress is security policy at durable-root authority, so read it
    // only after admission and bind it once before any capsule can load.
    let admitted_config = astrid_config::Config::load_with_home_and_layout(
        Some(&kernel.workspace_root),
        astrid_home.root(),
        kernel.workspace_layout(),
    )
    .map_err(|error| anyhow::anyhow!("Failed to load admitted-home boot policy: {error:#}"))?;
    kernel
        .bind_boot_local_egress(admitted_config.config.security.capsule_local_egress)
        .map_err(|error| anyhow::anyhow!("Failed to bind boot policy: {error}"))?;

    if defer_logging {
        init_logging(&log_config);
    }
    kernel
        .set_system_capsules(
            unified_cfg
                .as_ref()
                .into_iter()
                .flat_map(|config| config.uplinks.iter())
                .map(|uplink| uplink.plugin.clone()),
        )
        .await;

    // Astrid owns its baseline control plane. Start it before loading optional
    // distribution capsules so no capsule can race the canonical listener or
    // make a clean runtime unbootable by being absent or broken.
    let native_listener = kernel

View on GitHub (pinned to affd8760f4)