{"record":{"id":"a444beea71e1612c","repo":"astrid-runtime/astrid","slug":"workspace-capsule-directory-is-redirected","errorCode":null,"errorMessage":"workspace capsule directory is redirected: {}","messagePattern":"workspace capsule directory is redirected: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/wit.rs","lineNumber":221,"sourceCode":"        }\n        workspace.verify_tree(\"capsules\")?;\n    }\n\n    Ok(marks)\n}\n\n/// Read WIT marks from explicitly selected workspace capsule metadata.\n/// Principal installs are intentionally absent: their hashes come from the\n/// authenticated daemon registry query above.\nfn collect_from_capsules_dir(dir: &Path, marks: &mut HashSet<String>) -> anyhow::Result<()> {\n    for entry in std::fs::read_dir(dir)\n        .with_context(|| format!(\"failed to read workspace capsules: {}\", dir.display()))?\n    {\n        let entry = entry?;\n        let capsule_dir = entry.path();\n        let metadata = std::fs::symlink_metadata(&capsule_dir)?;\n        if metadata.file_type().is_symlink() {\n            anyhow::bail!(\n                \"workspace capsule directory is redirected: {}\",\n                capsule_dir.display()\n            );\n        }\n        if !metadata.is_dir() {\n            continue;\n        }\n        astrid_core::platform_fs::verify_no_redirects(&capsule_dir)?;\n        let meta_path = capsule_dir.join(\"meta.json\");\n        if std::fs::symlink_metadata(&meta_path).is_ok() {\n            astrid_core::platform_fs::verify_no_redirects(&meta_path)?;\n            if let Some(meta) = crate::commands::capsule::meta::read_meta(&capsule_dir) {\n                marks.extend(meta.wit_files.into_values());\n            }\n        }\n    }\n    Ok(())\n}","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/wit.rs#L203-L239","documentation":"This error is thrown by `collect_from_capsules_dir` while scanning a workspace's capsules directory to collect marks. It fires when a directory entry inside the workspace capsules dir is a symlink (`symlink_metadata` reports `is_symlink()`), which the tool treats as a redirect of a capsule directory outside the workspace and refuses to process rather than silently following it.","triggerScenarios":"Running a workspace-level command (via `collect_marks_in_workspace`) when any entry in the workspace capsules directory (e.g. `.astrid/capsules/<name>`) is a symbolic link instead of a real directory.","commonSituations":"Developers symlink capsule dirs from elsewhere on disk to share code across workspaces, or a package manager / dotfiles setup replaced a real capsule directory with a symlink; moving capsules to another drive and leaving links behind also triggers it.","solutions":["Remove the symlink and place a real capsule directory at that path (e.g. copy or move the actual directory back into the workspace capsules dir).","If the capsule was intentionally relocated, re-create the capsule in the workspace rather than linking to the external location.","Check all entries with `ls -la` in the workspace capsules directory and replace every symlink with a real directory before rerunning the command."],"exampleFix":"// before: capsule is a symlink pointing outside the workspace\nln -s ~/shared/my-capsule .astrid/capsules/my-capsule\n// after: use a real directory in the workspace\ncp -rL ~/shared/my-capsule .astrid/capsules/my-capsule","handlingStrategy":"validation","validationCode":"for entry in std::fs::read_dir(capsules_dir)? {\n    let p = entry?.path();\n    if std::fs::symlink_metadata(&p)?.file_type().is_symlink() {\n        eprintln!(\"skipping redirected capsule dir: {}\", p.display());\n        continue;\n    }\n}","typeGuard":"fn is_real_dir(p: &std::path::Path) -> bool {\n    match std::fs::symlink_metadata(p) {\n        Ok(m) => m.is_dir() && !m.file_type().is_symlink(),\n        Err(_) => false,\n    }\n}","tryCatchPattern":"match collect_marks_in_workspace(dir) {\n    Err(e) if e.to_string().contains(\"workspace capsule directory is redirected\") => {\n        eprintln!(\"fix the symlinked capsule dir before continuing: {e}\");\n    }\n    other => other?,\n}","preventionTips":["Never symlink directories into the workspace capsules dir; copy or move them instead.","Audit with `find .astrid/capsules -type l` before running workspace commands.","Document relocation procedures so capsules are moved, not linked."],"tags":["workspace","symlink","filesystem"],"backgroundTag":"path-traversal-blocked","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}