sigoden/aichat · error
Invalid path
Error message
Invalid path '{path_str}' What it means
parse_glob parses path patterns like 'dir/**/*.{rs,toml}'. When it finds a brace-like segment it cannot interpret as a '{ext,ext}' extension list, it bails with 'Invalid path'. Only comma-separated extensions inside braces are supported.
Solutions
- Use only comma-separated extensions inside braces: '*.{rs,toml}'
- Remove empty or single-item braces; use '*.rs' or '*' instead of '{}'
- Avoid spaces and nested braces inside the extension list
- Test the pattern with a simple glob like 'src/**/*.rs' first
Example fix
// before (invalid)
include = ["src/**/*{}", "docs/{md}']
// after
include = ["src/**/*.rs", "docs/*.md"] Defensive patterns
Strategy: validation
Validate before calling
const INVALID_EXT_BRACE = /\{\}|\{[^,}]*\}/;
function validGlob(p) {
const braces = p.match(/\{[^}]*\}/g) || [];
return braces.every(b => /^\{[\w]+(,[\w]+)*\}$/.test(b));
} Prevention
- Only use {a,b,c} brace groups with comma-separated extensions
- Never use empty braces; use '*' for all files
- Lint config glob patterns in CI
When it happens
Trigger: Calling path expansion (e.g. via config file patterns or expand_glob_paths) with a malformed extension group such as '{}', '{rs}', '{rs,}', nested braces, or braces used for something other than extensions.
Common situations: Typos in config glob patterns; copy-pasting shell brace expansion that the parser doesn't support; empty braces intending 'all files'.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09).
Data as JSON: /api/errors/bf2170d905b523bb.
Report an issue: GitHub.
Appendix: source
Thrown at src/utils/path.rs:135
.unwrap_or_default()
{
"/"
} else {
"."
}
.into();
}
let extensions = if let Some(curly_brace_end) = path_str[start..].find('}') {
let end = start + curly_brace_end;
let extensions_str = &path_str[start + offset..end + 1];
if extensions_str.starts_with('{') && extensions_str.ends_with('}') {
extensions_str[1..extensions_str.len() - 1]
.split(',')
.map(|s| s.to_string())
.collect::<Vec<String>>()
} else {
bail!("Invalid path '{path_str}'");
}
} else {
let extensions_str = &path_str[start + offset..];
vec![extensions_str.to_string()]
};
let extensions = if extensions.is_empty() {
None
} else {
Some(extensions)
};
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))
}
}
View on GitHub (pinned to 82976d349a)