{"record":{"id":"e6785561b1084fe9","repo":"zed-industries/zed","slug":"cd-directory-cd-was-not-in-any-root-director","errorCode":null,"errorMessage":"`cd` directory {cd:?} was not in any root directory in the project.","messagePattern":"`cd` directory (.+?) was not in any root directory in the project\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/agent/src/tools/terminal_tool.rs","lineNumber":1373,"sourceCode":"            None => Ok(None),\n        }\n    } else {\n        let path_style = project.path_style(cx);\n        let worktree_roots = project\n            .worktrees(cx)\n            .filter_map(|worktree| {\n                let worktree = worktree.read(cx);\n                // Skip single-file worktrees: a file can't be a working directory.\n                let root_dir = worktree.root_dir()?;\n                Some((worktree.root_name_str(), root_dir.to_path_buf()))\n            })\n            .collect::<Vec<_>>();\n\n        if let Some(dir) = resolve_cd_in_worktrees(cd, path_style, &worktree_roots) {\n            return Ok(Some(dir));\n        }\n\n        anyhow::bail!(\"`cd` directory {cd:?} was not in any root directory in the project.\");\n    }\n}\n\n/// Resolves a `cd` argument to an absolute worktree directory. `cd` may be a\n/// worktree's root name or an absolute path to a worktree or a subdirectory\n/// therein.\n///\n/// Absolute paths are classified with the project's [`PathStyle`] rather than\n/// the host's, so an absolute POSIX path resolves correctly on a Windows host\n/// driving a WSL/SSH project (#60040).\n///\n/// Both `cd` and the worktree roots are lexically normalized before prefix\n/// matching. This resolves `.` and `..` components up front, so a path that\n/// escapes a worktree does not have that worktree's root as a prefix and is\n/// rejected (#60014). On Windows-style projects it also unifies `/` and `\\`\n/// separators, since models frequently write `C:/foo/bar` for a root stored\n/// as `C:\\foo\\bar`.\nfn resolve_cd_in_worktrees(","sourceCodeStart":1355,"sourceCodeEnd":1391,"githubUrl":"https://github.com/zed-industries/zed/blob/f4178619acd0d47ea1f76a2025c42962c6d6638c/crates/agent/src/tools/terminal_tool.rs#L1355-L1391","documentation":"When an agent terminal command includes `cd <dir>`, the terminal tool collects every worktree's `(root_name, root_dir)` (skipping single-file worktrees, since a file cannot be a cwd) and calls `resolve_cd_in_worktrees`. If the `cd` target is neither a worktree root name nor an absolute path under any root, it bails with this message. Absolute paths are classified with the project's `PathStyle`, not the host's, so a Windows host can target WSL/SSH POSIX paths — but they must still be inside a root.","triggerScenarios":"The model emits `cd /some/path/outside/the/project`, `cd ../sibling-repo`, or `cd <name>` where `<name>` is not any worktree root name; also when every open worktree is a single file so the roots list is empty.","commonSituations":"The agent assumes a broader filesystem than the project allows; the user has one folder open but asks the agent to work in another; monorepo subdirectories are fine but sibling repos are not.","solutions":["Only `cd` to paths inside a currently open worktree, or to a worktree's root name.","Open the additional folder in the Zed project (multi-root) so its root becomes resolvable.","Use relative paths within the already-correct cwd instead of `cd`-ing out.","For remote/WSL projects, use the project's POSIX-style absolute path, not the host's path."],"exampleFix":"# agent terminal command\n# before\ncd /home/user/other-project && cargo test   # outside any root -> error\n# after (open other-project as a second worktree first)\ncd other-project && cargo test              # root name resolves","handlingStrategy":"validation","validationCode":"// Before emitting a cd, verify the target is a root name or under a root dir:\nlet roots: Vec<(String, PathBuf)> = project.worktrees(cx).iter().filter_map(|wt| {\n    let wt = wt.read(cx);\n    Some((wt.root_name_str().to_string(), wt.root_dir()?.to_path_buf()))\n}).collect();\nlet ok = roots.iter().any(|(name, dir)| cd == *name\n    || normalize(&resolve(cd)).starts_with(dir));\nif !ok { /* rewrite the command to stay inside a worktree */ }","typeGuard":"fn cd_resolves(cd: &str, roots: &[(String, PathBuf)]) -> bool {\n    roots.iter().any(|(name, dir)| {\n        cd == name || Path::new(cd).normalize().starts_with(dir)\n    })\n}","tryCatchPattern":"match run_terminal(cmd).await {\n    Err(e) if e.to_string().contains(\"was not in any root directory\") => {\n        // re-issue without the cd, or open the folder as a worktree first\n    }\n    rest => rest,\n}","preventionTips":["Give the agent the correct worktree root name instead of out-of-project absolute paths.","Open all needed folders as multi-root worktrees before driving the terminal.","Remember single-file worktrees cannot serve as cwd roots."],"tags":["rust","zed","agent","terminal","working-directory","worktree","cd"],"backgroundTag":"working-directory-outside-project","analyzedSha":"f4178619acd0d47ea1f76a2025c42962c6d6638c","analyzedAt":"2026-08-20T19:29:52.058Z","contentChangedAt":"2026-08-20T19:29:52.058Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}