astrid-runtime/astrid · error

capsule '{id}' provides an uplink but is absent from the ope

Error message

capsule '{id}' provides an uplink but is absent from the operator-owned [[uplinks]] allowlist

What it means

This error means a capsule manifest declares one or more uplinks (manifest.uplinks is non-empty), but the operator has not allowed the capsule's identity in the operator-owned [[uplinks]] allowlist (system_allowed was false). The kernel refuses to grant uplink residency to capsules that are not explicitly allowlisted, because an uplink grants network/egress reach out of the sandbox. It is an operator policy gate, not a bug in the capsule itself.

Source

Thrown at crates/astrid-kernel/src/lib.rs:552

enum RuntimeResidency {
    Principal,
    SystemResident,
}

impl RuntimeResidency {
    const fn is_system(self) -> bool {
        matches!(self, Self::SystemResident)
    }
}

fn classify_runtime_residency(
    manifest: &astrid_capsule_types::manifest::CapsuleManifest,
    id: &astrid_capsule_types::CapsuleId,
    system_allowed: bool,
) -> Result<RuntimeResidency, anyhow::Error> {
    let provides_uplink = !manifest.uplinks.is_empty();
    if provides_uplink && !system_allowed {
        anyhow::bail!(
            "capsule '{id}' provides an uplink but is absent from the \
             operator-owned [[uplinks]] allowlist"
        );
    }
    if system_allowed && (manifest.capabilities.uplink || provides_uplink) {
        Ok(RuntimeResidency::SystemResident)
    } else {
        Ok(RuntimeResidency::Principal)
    }
}

impl Kernel {
    async fn lock_capsule_view(
        &self,
        principal: &PrincipalId,
        capsule: &CapsuleId,
    ) -> CapsuleViewGuard {
        let key = CapsuleViewKey {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Have the operator add the capsule's id to the [[uplinks]] allowlist in the operator configuration, then retry
  2. Remove the [[uplinks]] entries from the capsule manifest if the capsule does not actually need network egress
  3. Verify the capsule id in the allowlist matches the manifest id exactly (spelling, case)
  4. If residency was expected to be non-system (user-resident), confirm which code path is passing system_allowed=false and whether an allowlist entry is genuinely required

Example fix

// before: operator config missing the capsule
[[uplinks]]
id = "some-other-capsule"

// after: allowlist the capsule that declares uplinks
[[uplinks]]
id = "your-capsule-id"
Defensive patterns

Strategy: validation

Validate before calling

if !manifest.uplinks.is_empty() && !operator_uplink_allowlist.contains(&manifest.package.id) {
    return Err("capsule declares uplinks but is not on the operator [[uplinks]] allowlist");
}

Try / catch

match result {
    Err(e) if e.to_string().contains("[[uplinks]] allowlist") => {
        // surface which allowlist entry is missing; do not retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling the residency-resolution function (used by load_capsule / prepare_runtime_replacement paths) with a manifest whose uplinks list is non-empty while the system_allowed flag is false — i.e., the operator's [[uplinks]] allowlist does not contain this capsule's id.

Common situations: A developer adds an [[uplinks]] entry to their Capsule.toml but the operator never added the capsule id to the host's uplink allowlist; the allowlist exists but the capsule id string doesn't match exactly (case/typo); after a fresh environment setup where the operator allowlist was not migrated.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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