astrid-runtime/astrid · error

workspace capsule tree contains an unsafe redirect: {error}

Error message

workspace capsule tree contains an unsafe redirect: {error}

What it means

Wraps a failure from `verify_tree` when checking that a directory inside the workspace state dir contains no symlinks or path components that redirect outside the tree. The kernel refuses to traverse a capsule tree that could be a symlink-escape vector. It is a security guard, not a functional bug.

Source

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

        .with_identity_store(Arc::clone(&kernel.identity_store))
        .with_access_resolver(access_resolver);
        drop(astrid_runtime::spawn(dispatcher.run()));

        debug_assert_eq!(
            kernel.event_bus.subscriber_count(),
            INTERNAL_SUBSCRIBER_COUNT,
            "INTERNAL_SUBSCRIBER_COUNT is stale; update it when adding permanent subscribers"
        );

        Ok(kernel)
    }

    fn verify_workspace_capsule_tree(&self, dir: &Path) -> anyhow::Result<()> {
        if let Ok(relative) = dir.strip_prefix(self.workspace_selection.state_dir()) {
            self.workspace_selection
                .verify_tree(relative)
                .map_err(|error| {
                    anyhow::anyhow!("workspace capsule tree contains an unsafe redirect: {error}")
                })?;
        }
        Ok(())
    }

    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    fn verify_workspace_component_paths(
        &self,
        dir: &Path,
        manifest: &astrid_capsule_types::manifest::CapsuleManifest,
    ) -> anyhow::Result<()> {
        let Ok(capsule_relative) = dir.strip_prefix(self.workspace_selection.state_dir()) else {
            return Ok(());
        };
        for component in &manifest.components {
            if component.path.is_absolute() {
                anyhow::bail!(
                    "workspace capsule component must be relative: {}",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Find the offending entry reported by the inner error and replace the symlink with a real file/directory
  2. Re-extract or reinstall the capsule archive with symlink preservation disabled (e.g. tar --no-same-owner without -h)
  3. Remove the stale capsule directory under the workspace state dir and let the kernel re-materialize it
  4. Inspect verify_tree in astrid-kernel to confirm which path component failed before deleting data

Example fix

// before: capsule tree contains symlink
state_dir/capsules/foo -> /etc/something
// after
rm state_dir/capsules/foo && mkdir state_dir/capsules/foo && # re-extract real files into it
Defensive patterns

Strategy: validation

Validate before calling

let rel = dir.strip_prefix(workspace_selection.state_dir())?;
if let Err(e) = workspace_selection.verify_tree(rel) {
    // reject before handing to kernel
    return Err(e);
}

Type guard

fn is_under_state_dir(dir: &Path, state_dir: &Path) -> bool {
    dir.strip_prefix(state_dir).is_ok()
}

Prevention

When it happens

Trigger: Calling workspace capsule verification (verify_workspace_capsule_tree) when `dir` sits under workspace_selection.state_dir() and verify_tree finds a symlink or redirect component inside the relative tree.

Common situations: A capsule was extracted with symlinks preserved from an archive; a user hand-linked cache/state directories to another disk; a previous partial install left dangling links; shared state dirs synced via tools that materialize symlinks.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


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