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

  1. Use only comma-separated extensions inside braces: '*.{rs,toml}'
  2. Remove empty or single-item braces; use '*.rs' or '*' instead of '{}'
  3. Avoid spaces and nested braces inside the extension list
  4. 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

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)