sigoden/aichat · error · anyhow::Error
Not found
Error message
Not found '{}' What it means
list_files walks a path (recursively when called from expand_glob_paths) and bails with "Not found '<path>'" when the entry does not exist and bail_non_exist is true. It is a strict-existence check so glob expansion fails fast on missing roots.
Solutions
- Verify the path in the message exists relative to the working directory
- Fix the typo or update the config path after renaming/moving files
- Remove stale entries pointing at deleted files
- Use an absolute path or adjust the base directory if CWD differs
Example fix
// before include = ["srcs/**/*.rs"] // typo: no 'srcs' dir // after include = ["src/**/*.rs"]
Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function assertPathsExist(paths) {
for (const p of paths) {
if (!fs.existsSync(p.split('*')[0].replace(/[^/]*$/, '') || '.')) {
throw new Error(`base path missing for ${p}`);
}
}
} Prevention
- Use paths relative to the repo root and run from there
- Update config when files are moved or deleted
- Watch out for case-sensitive filesystems
When it happens
Trigger: Expanding glob patterns whose base directory doesn't exist, or a config including a file path that was deleted/renamed, with the bail-on-missing option enabled.
Common situations: Typos in configured include paths; repository layout changed after config was written; running from a different working directory than the config assumes; case-sensitivity mismatches on Linux.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09).
Data as JSON: /api/errors/3488bddf0de68f27.
Report an issue: GitHub.
Appendix: source
Thrown at src/utils/path.rs:164
Ok((base_path, extensions, current_only))
} else if path_str.ends_with("/**") || path_str.ends_with(r"\**") {
Ok((path_str[0..path_str.len() - 3].to_string(), None, false))
} else {
Ok((path_str.to_string(), None, false))
}
}
#[async_recursion::async_recursion]
async fn list_files(
files: &mut IndexSet<String>,
entry_path: &Path,
suffixes: Option<&Vec<String>>,
current_only: bool,
bail_non_exist: bool,
) -> Result<()> {
if !entry_path.exists() {
if bail_non_exist {
bail!("Not found '{}'", entry_path.display());
} else {
return Ok(());
}
}
if entry_path.is_dir() {
let mut reader = tokio::fs::read_dir(entry_path).await?;
while let Some(entry) = reader.next_entry().await? {
let path = entry.path();
if path.is_dir() {
if !current_only {
list_files(files, &path, suffixes, current_only, bail_non_exist).await?;
}
} else {
add_file(files, suffixes, &path);
}
}
} else {
add_file(files, suffixes, entry_path);View on GitHub (pinned to 82976d349a)