astrid-runtime/astrid · error

workspace state directory escapes or redirects outside its…

Error message

workspace state directory escapes or redirects outside its selected path: {}

What it means

After canonicalizing the state directory, the library verifies it resolves to exactly the literal path requested and that its parent is the project root. Any symlink component, aliased path, or a directory whose parent is not `project_root` triggers this error, blocking state from escaping its designated location.

Solutions

  1. Set the state path to a plain relative path directly under the project root, with no symlinks or `..` components.
  2. Move the directory back inside the project root.
  3. Clear environment overrides (e.g. TMPDIR-style env vars) that make the canonical path differ from the literal one.

Example fix

// before
state_dir = "/var/lib/astrid/project-state"
// after
state_dir = ".astrid/state"
Defensive patterns

Strategy: validation

Validate before calling

fn inside_project_root(state_dir: &std::path::Path, root: &std::path::Path) -> bool {
    let canonical = std::fs::canonicalize(state_dir).ok();
    canonical.as_deref() == Some(state_dir)
        && canonical.and_then(|c| c.parent()).map(|p| p == root).unwrap_or(false)
}

Type guard

fn resolves_to_configured_path(p: &std::path::Path) -> bool {
    std::fs::canonicalize(p).map(|c| c == p).unwrap_or(false)
}

Try / catch

match resolve(...) {
    Err(e) if e.to_string().contains("escapes or redirects") => {
        // fall back to default relative state path under project root
        resolve(...)
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `resolve` when `std::fs::canonicalize(state_dir)` differs from `state_dir` (symlinks, non-normalized path) or when the canonical path's parent is not `project_root` (path placed outside the project).

Common situations: Config uses an absolute path or `/../` traversal pointing elsewhere; the state dir is a symlink target (resolves differently than spelled); user moved the state dir outside the project tree.

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/45700f1c547ebaea. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-core/src/workspace_security.rs:318

    crate::platform_fs::verify_no_redirects(state_dir)?;
    let metadata = match std::fs::symlink_metadata(state_dir) {
        Ok(metadata) => metadata,
        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
        Err(error) => return Err(error),
    };
    if metadata.file_type().is_symlink() || !metadata.is_dir() {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "workspace state path must be a real directory, not a redirect or file: {}",
                state_dir.display()
            ),
        ));
    }

    let canonical = std::fs::canonicalize(state_dir)?;
    if canonical != state_dir || canonical.parent() != Some(project_root) {
        return Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!(
                "workspace state directory escapes or redirects outside its selected path: {}",
                state_dir.display()
            ),
        ));
    }
    Ok(())
}

/// Stable identity for one project root and workspace layout selection.
///
/// The identity is suitable for detecting whether a CLI and an already-running
/// daemon selected the same project. It does not expose the project path.
#[must_use]
pub fn workspace_selection_fingerprint(
    project_root: &Path,
    workspace_layout: &WorkspaceLayout,

View on GitHub (pinned to affd8760f4)