astrid-runtime/astrid · error

principal capsule removal must go through the authenticated

Error message

principal capsule removal must go through the authenticated daemon

What it means

remove_capsule refuses to remove a capsule that is not scoped to the workspace: only workspace capsules may be removed directly by the CLI. Principal (user-level) capsules are managed by the authenticated daemon, so the CLI blocks local removal to avoid bypassing daemon-side authentication and state. This is an intentional guard, not a failure of the removal itself.

Source

Thrown at crates/astrid-cli/src/commands/capsule/remove.rs:30

use astrid_core::PrincipalId;
use astrid_core::dirs::AstridHome;

use super::meta::CapsuleMeta;

/// Remove an installed capsule by name.
///
/// The caller must run [`validate_capsule_removal`] before any live unload and
/// this on-disk deletion. Keeping deletion validation-free avoids a second
/// dependency scan after daemon unload and prevents a stale second snapshot
/// from disagreeing with the already-authorized operation.
pub(crate) fn remove_capsule(
    name: &str,
    workspace: bool,
    force: bool,
    purge: bool,
) -> anyhow::Result<()> {
    if !workspace {
        bail!("principal capsule removal must go through the authenticated daemon");
    }
    let home = AstridHome::resolve()?;
    let principal = crate::principal::current();
    remove_capsule_from_home_for(&home, &principal, name, workspace, force, purge)
}

fn remove_capsule_from_home(
    home: &AstridHome,
    name: &str,
    workspace: bool,
    force: bool,
    purge: bool,
) -> anyhow::Result<()> {
    let principal = astrid_capsule_install::paths::install_principal();
    remove_capsule_from_home_for(home, &principal, name, workspace, force, purge)
}

fn remove_capsule_from_home_for(

View on GitHub (pinned to affd8760f4)

Solutions

  1. If the capsule lives in the current workspace, re-run with the workspace flag: astrid capsule remove <name> --workspace.
  2. For principal capsules, perform the removal through the authenticated daemon path (daemon-managed remove command) instead of the CLI-local path.
  3. Verify with capsule list which scope the capsule belongs to before removing.

Example fix

// before
remove_capsule(name, false, force, purge).await?
// after
remove_capsule(name, true, force, purge).await?  // workspace-scoped removal
Defensive patterns

Strategy: validation

Validate before calling

// pick the right removal path up front
let is_workspace_capsule = workspace_root.join("capsules").join(name).exists();
if !is_workspace_capsule {
    eprintln!("principal capsule: route removal through the authenticated daemon");
}

Type guard

fn requires_daemon_removal(workspace: bool) -> bool { !workspace }

Try / catch

if let Err(e) = remove_capsule(...).await {
    if e.to_string().contains("authenticated daemon") {
        // switch to the daemon-managed removal command
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling capsule remove without the workspace flag (workspace == false), so the code takes the principal-capsule path and bails immediately.

Common situations: Users omitting --workspace when the capsule they see is actually a workspace capsule registered differently; scripting removals against principal capsules; migration from older CLIs that allowed local principal removal.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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