{"record":{"id":"ca626891a58090f1","repo":"Hmbown/CodeWhale","slug":"search-root-does-not-exist","errorCode":null,"errorMessage":"search root does not exist: {}","messagePattern":"search root does not exist: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/eval.rs","lineNumber":622,"sourceCode":"fn read_workspace_file(path: &Path) -> Result<String> {\n    fs::read_to_string(path).with_context(|| format!(\"failed to read {}\", path.display()))\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct SearchMatch {\n    path: PathBuf,\n    line: usize,\n    content: String,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct SearchResult {\n    matches: Vec<SearchMatch>,\n}\n\nfn search_files(root: &Path, pattern: &str) -> Result<SearchResult> {\n    if !root.exists() {\n        return Err(anyhow!(\"search root does not exist: {}\", root.display()));\n    }\n\n    let regex = Regex::new(pattern).context(\"failed to compile search regex\")?;\n    let mut matches = Vec::new();\n\n    let walker = WalkBuilder::new(root)\n        .hidden(false)\n        .git_ignore(false)\n        .git_global(false)\n        .git_exclude(false)\n        .build();\n\n    for entry in walker {\n        let entry = entry.with_context(|| format!(\"failed to walk {}\", root.display()))?;\n        if !entry.file_type().is_some_and(|t| t.is_file()) {\n            continue;\n        }\n","sourceCodeStart":604,"sourceCodeEnd":640,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/eval.rs#L604-L640","documentation":"`search_files` (crates/tui/src/eval.rs:622) refuses to build a walker when `root.exists()` is false. The check runs before regex compilation, so a bad root surfaces as a path problem rather than a pattern problem.","triggerScenarios":"A Grep-style eval tool call passes a root directory that was never created, was deleted mid-run, or is mistyped (an absolute path resolved against the wrong cwd, or a path built from an empty variable).","commonSituations":"Root computed from an empty config field or env var; workspace cleaned between steps; case mismatch on a case-sensitive filesystem.","solutions":["Create the directory or correct the root path passed to the search","Guard callers with `root.try_exists()` before searching","Log the resolved absolute root before invoking the search"],"exampleFix":"// before\nlet results = search_files(&root, pattern)?;\n// after\nanyhow::ensure!(root.is_dir(), \"missing search root {}\", root.display());\nlet results = search_files(&root, pattern)?;","handlingStrategy":"validation","validationCode":"match root.try_exists() {\n    Ok(true) => {}\n    Ok(false) => std::fs::create_dir_all(&root)?,\n    Err(err) => return Err(err.into()),\n}","typeGuard":"fn searchable_root(root: &std::path::Path) -> bool {\n    root.is_dir()\n}","tryCatchPattern":null,"preventionTips":["Canonicalize roots early and pass absolute paths","Create directories during setup rather than implicitly at search time","Distinguish 'no matches' from 'root missing' in caller logic"],"tags":["filesystem","search","path","validation"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}