astrid-runtime/astrid · error

native capsule runtime requires the authoritative principal…

Error message

native capsule runtime requires the authoritative principal store

What it means

This error is thrown by the kernel's native capsule runtime builder when the AstridKernel was constructed without an authoritative principal store. The principal store is the source of truth for capsule ownership per principal, so the runtime refuses to start without it rather than run with no authority over principals. It is a fail-fast guard in `with_principal_storage(...)` during runtime assembly.

Solutions

  1. Set the principal store on the kernel before starting the native capsule runtime, via the builder method that populates `principal_store`
  2. Check the kernel construction code path and ensure `with_principal_storage`-equivalent configuration is always applied
  3. If the runtime is intentionally principal-less, use a runtime mode that does not require the authoritative store instead of the native capsule runtime

Example fix

// before
let kernel = AstridKernel::builder().build();
kernel.start_native_capsule_runtime().await?; // panics into anyhow: no principal store
// after
let kernel = AstridKernel::builder()
    .with_principal_store(principal_store)
    .build();
kernel.start_native_capsule_runtime().await?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust, before starting the runtime
if kernel.principal_store().is_none() {
    return Err(anyhow!("principal store must be configured before native capsule runtime"));
}

Type guard

fn has_principal_store(kernel: &AstridKernel) -> bool {
    kernel.principal_store().is_some()
}

Prevention

When it happens

Trigger: Calling the kernel method that starts the native capsule runtime (lib.rs:1940, the builder chain ending in `with_astrid_workspace()`) while `self.principal_store` is `None` — i.e. the kernel was built via a path that never called the principal-store setter, or the field was explicitly left unset.

Common situations: Constructing AstridKernel with a minimal/partial builder configuration in tests or embedded setups; refactoring that renamed or dropped the principal-store builder call; instantiating the kernel for a use case (e.g. headless tooling) that skipped principal storage but then attempted to launch capsules.

Understand the failure class

Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — 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/bc70177641f3237d. Report an issue: GitHub.

Appendix: source

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

        let capsule_listener = (!self.native_uplink_owns_listener.load(Ordering::Acquire))
            .then(|| self.cli_socket_listener.clone())
            .flatten();
        let mut ctx = astrid_capsule::context::CapsuleContext::new(
            load_principal,
            self.workspace_root.clone(),
            // Durable home VFS authority is threaded separately through the
            // UID-bound principal store. Do not pass a native PrincipalHome
            // path into the steady-state capsule context.
            None,
            kv,
            Arc::clone(&self.event_bus),
            capsule_listener,
        )
        .with_astrid_workspace()
        .with_principal_storage(
            self.principal_store.clone().ok_or_else(|| {
                anyhow::anyhow!(
                    "native capsule runtime requires the authoritative principal store"
                )
            })?,
            self.principal_directory.clone(),
        )
        .with_workspace_branches(self.workspace_branches.clone().ok_or_else(|| {
            anyhow::anyhow!(
                "canonical Astrid workspace requires the kernel workspace branch service"
            )
        })?)
        .with_process_storage_mount_broker(
            self.process_storage_mount_broker
                .get()
                .cloned()
                .ok_or_else(|| anyhow::anyhow!("native process storage mount broker unavailable"))?,
        )
        .with_registry(Arc::clone(&self.capsules))
        .with_session_token(Arc::clone(&self.session_token))

View on GitHub (pinned to affd8760f4)