{"record":{"id":"db6a7e8c2526dffb","repo":"astrid-runtime/astrid","slug":"workspace-root-is-not-a-directory","errorCode":null,"errorMessage":"workspace root is not a directory: {}","messagePattern":"workspace root is not a directory: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/workspace_security.rs","lineNumber":36,"sourceCode":"    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\n        let state_dir = project_root.join(layout.state_dir_name());\n        verify_state_dir_path(&project_root, &state_dir)?;\n        Ok(Self {\n            project_root,\n            state_dir,\n            layout,\n        })\n    }\n\n    /// Canonical project root used by every workspace filesystem consumer.","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/workspace_security.rs#L18-L54","documentation":"After canonicalizing the project root and verifying it does not redirect through symlinks, WorkspaceSelection::resolve stats the path and rejects it with InvalidInput if it is not a directory. A workspace root must be an actual directory; pointing it at a regular file (or special file) is a configuration error.","triggerScenarios":"Calling WorkspaceSelection::resolve with a project_root that canonicalizes to a regular file, FIFO, socket, or device node instead of a directory.","commonSituations":"Config pointing at a file like project.toml instead of the project directory; a mount or symlink swapping the directory for a file; automation passing the wrong variable (file path vs directory path).","solutions":["Point project_root at the workspace directory, not a file inside it.","If the directory was replaced by a file, restore it (recreate the directory and move contents back).","Add an is_dir() precheck on the configured path before constructing the workspace selection.","Fix mounts/symlinks that shadow the intended directory."],"exampleFix":"// before\nlet sel = WorkspaceSelection::resolve(Path::new(\"/srv/app/Cargo.toml\"), layout)?;\n// after\nlet sel = WorkspaceSelection::resolve(Path::new(\"/srv/app\"), layout)?;","handlingStrategy":"validation","validationCode":"let meta = std::fs::metadata(&root)?;\nassert!(meta.is_dir(), \"project root must be a directory: {}\", root.display());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate configured roots point at directories at startup","Distinguish file-path vs directory-path config fields clearly","Prefer canonical paths from a single source of truth in configuration"],"tags":["io","filesystem","validation","workspace"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}