astrid-runtime/astrid · error

resolve durable principal UID

Error message

resolve durable principal UID: {error}

What it means

run_lifecycle_for_principal_with_storage resolves the durable principal's UID via the principal directory before running lifecycle operations; if uid_for fails (directory corruption, missing mapping), the underlying error is wrapped as 'resolve durable principal UID: {error}' with full context.

Solutions

  1. Register the principal (or run an initial install) before lifecycle operations
  2. Verify the principal identifier matches the registered one exactly
  3. Repair or rebuild the principal directory storage
  4. Inspect the wrapped {error} message for the underlying cause
Defensive patterns

Strategy: try-catch

Validate before calling

fn principal_registered(storage: &Storage, p: &Principal) -> bool {
    storage.principal_directory().uid_for(p).is_ok()
}

Try / catch

match run_lifecycle_for_principal_with_storage(...) {
    Err(e) if e.to_string().starts_with("resolve durable principal UID") => {
        eprintln!("principal not registered in directory: register it first");
    }
    other => other?,
}

Prevention

When it happens

Trigger: install_from_local_path_internal invokes the lifecycle runner for a target_principal whose entry is absent or unreadable in storage.principal_directory(), so uid_for returns an Err.

Common situations: Installing/upgrading a capsule for a principal that was never registered; damaged principal-directory index on disk; principal identifier casing/format mismatch.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-capsule-install/src/lifecycle.rs:157

/// directory. The immutable UID is resolved before any secret scope is built;
/// callers that only have a mutable alias must use this entry point rather
/// than deriving a namespace from alias text.
#[allow(clippy::too_many_arguments)]
pub fn run_lifecycle_for_principal_with_storage(
    target_dir: &Path,
    wasm_bytes: Vec<u8>,
    manifest: &CapsuleManifest,
    home: &AstridHome,
    target_principal: &PrincipalId,
    storage: &RuntimePrincipalStore,
    phase: LifecyclePhase,
    previous_version: Option<&str>,
    external_bus: Option<EventBus>,
) -> anyhow::Result<()> {
    let directory = storage.principal_directory();
    let uid = directory
        .uid_for(target_principal)
        .map_err(|error| anyhow::anyhow!("resolve durable principal UID: {error}"))?;
    run_lifecycle_in_scope(
        target_dir,
        wasm_bytes,
        manifest,
        Some(home),
        target_principal,
        Some(uid),
        Some(storage.clone()),
        phase,
        previous_version,
        external_bus,
    )
}

#[allow(clippy::too_many_arguments)]
fn run_lifecycle_in_scope(
    target_dir: &Path,
    wasm_bytes: Vec<u8>,

View on GitHub (pinned to affd8760f4)