{"record":{"id":"9a2fc6ba117fd672","repo":"astrid-runtime/astrid","slug":"failed-to-resolve-workspace-root-error","errorCode":null,"errorMessage":"failed to resolve workspace root {}: {error}","messagePattern":"failed to resolve workspace root (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/workspace_security.rs","lineNumber":26,"sourceCode":"use super::WorkspaceLayout;\n\n/// A checked project workspace selection.\n///\n/// The project root is canonical and the selected state directory is either\n/// absent or a real directory directly beneath that root. Symlinks, junctions,\n/// and other redirects are rejected by requiring an existing directory to\n/// canonicalize to the exact direct-child path selected here.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct WorkspaceSelection {\n    project_root: PathBuf,\n    state_dir: PathBuf,\n    layout: WorkspaceLayout,\n}\n\nimpl WorkspaceSelection {\n    pub(super) fn resolve(project_root: &Path, layout: WorkspaceLayout) -> io::Result<Self> {\n        let project_root = std::fs::canonicalize(project_root).map_err(|error| {\n            io::Error::new(\n                error.kind(),\n                format!(\n                    \"failed to resolve workspace root {}: {error}\",\n                    project_root.display()\n                ),\n            )\n        })?;\n        crate::platform_fs::verify_no_redirects(&project_root)?;\n        if !std::fs::metadata(&project_root)?.is_dir() {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\n                    \"workspace root is not a directory: {}\",\n                    project_root.display()\n                ),\n            ));\n        }\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/workspace_security.rs#L8-L44","documentation":"WorkspaceSelection::resolve canonicalizes the supplied project_root to obtain the true absolute workspace root, and wraps any std::fs::canonicalize failure (not-found, permission denied, symlink loop, I/O error) in an io::Error preserving the original kind while adding context: the unresolved path and the underlying OS error. The library cannot establish a trusted workspace root without a canonical path.","triggerScenarios":"Calling WorkspaceSelection::resolve (directly or via ensure_state_dir / resolve_directory / resolve_file / verify) with a project_root that does not exist, is unreadable due to permissions, sits behind a broken symlink, or contains a symlink loop.","commonSituations":"Typo in the configured project root; running before project initialization created the directory; the workspace was deleted or moved while the process held a stale path; NFS/network mounts returning EIO; restrictive file permissions after a container user switch.","solutions":["Create the project root directory if it does not exist (std::fs::create_dir_all) before resolving the workspace.","Fix the configured project root path (typo, wrong cwd, relative path resolved from an unexpected working directory).","Repair or remove broken symlinks along the path.","Check permissions on every path component so the process can traverse to the root.","Investigate the wrapped OS error in the message (e.g. ENOENT vs EACCES vs ELOOP) to target the exact cause."],"exampleFix":"// before\nlet sel = WorkspaceSelection::resolve(Path::new(\"/opt/missing-project\"), layout)?;\n// after\nlet root = Path::new(\"/opt/my-project\");\nstd::fs::create_dir_all(root)?;\nlet sel = WorkspaceSelection::resolve(root, layout)?;","handlingStrategy":"validation","validationCode":"fn root_ready(p: &Path) -> std::io::Result<()> {\n    let meta = std::fs::metadata(p).map_err(|e| e)?;\n    if !meta.is_dir() { return Err(io::Error::new(io::ErrorKind::InvalidInput, \"not a dir\")); }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match WorkspaceSelection::resolve(root, layout) {\n    Err(e) => { log::error!(\"cannot resolve workspace root: {e}\"); return Err(e); }\n    Ok(sel) => sel,\n}","preventionTips":["create_dir_all the project root before resolving","Resolve relative roots against an explicit, fixed current directory","Avoid symlinked project roots or canonicalize early and reuse the result","Check the wrapped OS error kind (ENOENT/EACCES/ELOOP) to diagnose quickly"],"tags":["io","filesystem","path-resolution","workspace"],"backgroundTag":"file-not-found","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"}