can1357/oh-my-pi · error

err.to_string() (invalid exclude glob pattern)

Error message

err.to_string() (invalid exclude glob pattern)

What it means

fd compiles each --exclude pattern with GlobBuilder (literal_separator(true)); invalid exclude globs fail compilation and are converted to InvalidInput with err.to_string(). Note excludes always use glob syntax and are case-sensitive here (no case_insensitive flag is passed).

Source

Thrown at crates/pi-builtins/src/fd.rs:1250

		let regex = RegexBuilder::new(&pattern)
			.case_insensitive(case_insensitive)
			.build()
			.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))?;
		regexes.push(regex);
	}
	Ok(SearchMatcher::Regex(regexes))
}

fn build_excludes(patterns: &[String]) -> io::Result<Excludes> {
	if patterns.is_empty() {
		return Ok(Excludes::empty());
	}
	let mut matchers = Vec::with_capacity(patterns.len());
	for pattern in patterns {
		let glob = GlobBuilder::new(pattern)
			.literal_separator(true)
			.build()
			.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err.to_string()))?;
		matchers.push(glob.compile_matcher());
	}
	Ok(Excludes(Arc::new(matchers)))
}

fn build_type_filter(types: &[String]) -> io::Result<TypeFilter> {
	let mut filter = TypeFilter::default();
	for value in types {
		match value.as_str() {
			"f" | "file" => filter.regular = true,
			"d" | "dir" | "directory" => filter.directory = true,
			"l" | "symlink" => filter.symlink = true,
			"s" | "socket" => filter.socket = true,
			"p" | "pipe" => filter.pipe = true,
			"b" | "block-device" => filter.block = true,
			"c" | "char-device" => filter.character = true,
			"x" | "executable" => filter.executable = true,
			"e" | "empty" => filter.empty = true,

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the exclude glob syntax (balance []/{}, escape literal specials)
  2. Quote/escape patterns loaded from config; filter invalid entries before passing them
  3. Use --fixed-strings on the include side and translate exclusions to valid globs (e.g. `**/name`)
  4. Validate patterns with a glob library before generating the command

Example fix

// before
fd . --exclude 'node_modules('  // invalid paren
// after
fd . --exclude '**/node_modules/**'
Defensive patterns

Strategy: validation

Validate before calling

use glob::Pattern;fn validate_excludes(pats: &[String]) -> Result<(), String> { for p in pats { Pattern::new(p).map_err(|e| format!("exclude '{}': {}", p, e))?; } Ok(()) }

Type guard

fn is_exclude_glob_error(msg: &str) -> bool { msg.contains("error parsing glob") }

Try / catch

let excludes = build_excludes(&patterns).map_err(|e| format!("fd: bad --exclude: {}", e))?;

Prevention

When it happens

Trigger: `fd pattern --exclude '['` or `--exclude 'a{b'` — unbalanced character classes/braces or dangling escapes in exclusion globs.

Common situations: Exclude lists generated from config files where some entries aren't valid globs, unescaped brackets in patterns meant to match literal filenames (e.g. `foo[1]`), or Windows-style backslash paths used as globs.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/abb00724d713a291. Report an issue: GitHub.