astrid-runtime/astrid · error

capsule ' ' is outside the explicit workspace portal and…

Error message

capsule {operation} '{}' is outside the explicit workspace portal and has no durable registry authority

What it means

capture_bound_materialization first tries to bind the capsule to a durable registry publication (published_capsule_snapshot + repair) and then falls back to verifying the directory's installed authority. If neither applies — the registry verification fails AND a durable principal store exists but the target directory lies outside the explicit workspace state dir — the kernel refuses the operation: the capsule would run from an arbitrary path with no durable authority backing it, bypassing the workspace portal.

Solutions

  1. Load the capsule from inside the explicit workspace portal (a path under workspace_selection.state_dir()) or install/publish it into the durable registry so verify_registry_materialization succeeds.
  2. Publish the capsule (register its snapshot and authority with the principal store) before attempting load_capsule/prepare_runtime_replacement on that path.
  3. Verify the workspace state_dir configuration matches where the capsule is actually materialized; a path-prefix mismatch alone triggers this bail.
  4. If a locally built capsule must run, route it through the workspace portal directory (copy/materialize it under state_dir) rather than passing its build path directly.

Example fix

// before: loading a capsule from an arbitrary path
let manifest = kernel.load_capsule(Path::new("/tmp/build/my-capsule"), &principal)?;

// after: load from inside the workspace portal state dir
let portal_dir = kernel.workspace_selection.state_dir().join("my-capsule");
let manifest = kernel.load_capsule(&portal_dir, &principal)?;
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the capsule lives in the workspace portal before loading
let state_dir = kernel.workspace_selection.state_dir();
let dir = std::fs::canonicalize(&dir)?;
let state_dir = std::fs::canonicalize(state_dir)?;
if !dir.starts_with(state_dir) {
    anyhow::bail!("capsule must be published or placed under the workspace state dir");
}

Type guard

fn inside_workspace(dir: &Path, state_dir: &Path) -> bool {
    match (std::fs::canonicalize(dir), std::fs::canonicalize(state_dir)) {
        (Ok(d), Ok(s)) => d.starts_with(s),
        _ => false,
    }
}

Try / catch

match kernel.load_capsule(&dir, &principal) {
    Err(e) if e.to_string().contains("outside the explicit workspace portal") => {
        publish_to_registry(&manifest)?; // or move capsule under state_dir
        kernel.load_capsule(&dir, &principal)
    }
    other => other,
}

Prevention

When it happens

Trigger: load_capsule or prepare_runtime_replacement is called with a `dir` such that published_capsule_snapshot finds no publication, verify_registry_materialization returns false, self.principal_store is Some, and dir does not start with self.workspace_selection.state_dir() — e.g. loading a capsule from /tmp/my-capsule or another project folder while a durable registry is configured.

Common situations: A developer points the loader at a local checkout/build-output directory instead of an installed or workspace-portal capsule; the workspace state dir is misconfigured (different path than where capsules were installed); a capsule was installed before the durable principal store was enabled and now lives outside the portal; CI copies capsule directories to scratch paths outside the workspace.

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

Appendix: source

Thrown at crates/astrid-kernel/src/capsule_materialization.rs:141

        if let Some(snapshot) = snapshot {
            let runtime_dir = self.published_cache_target(principal, manifest, &snapshot)?;
            let bound_manifest = self.repair_published_materialization(
                &runtime_dir,
                principal,
                manifest,
                &snapshot,
            )?;
            return Ok(Some(BoundMaterialization {
                snapshot,
                runtime_dir,
                manifest: bound_manifest,
            }));
        }
        if !self.verify_registry_materialization(dir, principal, manifest)? {
            if self.principal_store.is_some()
                && !dir.starts_with(self.workspace_selection.state_dir())
            {
                anyhow::bail!(
                    "capsule {operation} '{}' is outside the explicit workspace portal and \
                     has no durable registry authority",
                    manifest.package.name
                );
            }
            self.verify_installed_authority_for_runtime(dir, manifest).map_err(|error| {
                anyhow::anyhow!(
                    "capsule {operation} '{}' exceeds or cannot prove its installed authority: {error:#}",
                    manifest.package.name
                )
            })?;
        }
        Ok(None)
    }

    /// Repair a stale or missing cache generation from one exact snapshot.
    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    pub(crate) fn ensure_published_materialization(

View on GitHub (pinned to affd8760f4)