facebook/relay · error

Invalid glob pattern

Error message

Invalid glob pattern '{}': {}

What it means

load_schema expands each entry of schema_paths as a glob pattern via the glob crate. If a pattern is malformed (e.g. unbalanced brackets, invalid recursion syntax), glob::glob returns an error which is wrapped as 'Invalid glob pattern'. The whole load fails before any file is read.

Solutions

  1. Inspect the pattern echoed in the error and fix its glob syntax (balance brackets, valid wildcards *, ?, **).
  2. Test the pattern in isolation (glob::glob(&pattern).unwrap()) before wiring it into config.
  3. If the path is meant to be literal, escape glob metacharacters or ensure it contains no [ ] { } characters.
  4. Validate patterns at config-load time with a small helper that calls glob::glob and reports a friendly error.

Example fix

// before
load_schema(vec!["schemas/**[".to_string()])?; // invalid pattern
// after
load_schema(vec!["schemas/**/*.graphql".to_string()])?;
Defensive patterns

Strategy: validation

Validate before calling

fn valid_glob(pattern: &str) -> bool {
    glob::glob(pattern).is_ok()
}
// assert all patterns compile before calling load_schema
for p in &schema_paths {
    assert!(valid_glob(p), "invalid glob pattern: {p}");
}

Try / catch

let schema = load_schema(paths.clone()).map_err(|e| {
    if e.to_string().starts_with("Invalid glob pattern") {
        anyhow!("config error: check schema_paths globs: {e}")
    } else { e }
});

Prevention

When it happens

Trigger: Calling load_schema(vec![pattern]) or compare() with a pattern string the glob crate cannot compile — e.g. "schema/**[" or "[a-" ; empty or mis-escaped patterns.

Common situations: Config files or CLI args where patterns are hand-typed with typos; patterns interpolated from variables that contain stray '[' or ']'; Windows-style backslash paths mixed into glob syntax.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/c2788e16b575b154. Report an issue: GitHub.

Appendix: source

Thrown at compiler/crates/graphql-ir-diff/src/lib.rs:804

            // allows parsing of "query {...}" with no name, all other options are default
            default_anonymous_operation_name: Some("Anonymous".intern()),
            allow_custom_scalar_literals: true,
        },
    )
    .map_err(|diagnostics| anyhow::anyhow!(diagnostics.iter().join("\n")))?;

    Ok(Program::from_definitions(schema, ir))
}

pub fn load_schema(schema_paths: Vec<String>) -> Result<Arc<SDLSchema>> {
    // Collect (content, file_path) pairs for each schema file
    let schema_files: Vec<(String, String)> = schema_paths
        .clone()
        .into_iter()
        .map(|pattern| {
            // expand if path contains "*"
            let paths = glob::glob(&pattern)
                .map_err(|e| anyhow!("Invalid glob pattern '{}': {}", pattern, e))?;
            let file_entries: Result<Vec<(String, String)>> = paths
                .map(|entry| {
                    let file_path =
                        entry.map_err(|e| anyhow!("Failed to read glob entry: {}", e))?;
                    let file_path_str = file_path.to_string_lossy().to_string();
                    let schema_bytes = fs::read(file_path)?;
                    let content = String::from_utf8(schema_bytes)
                        .map_err(|e| anyhow!("Cannot parse schema utf8 from bytes: {}", e))?;
                    Ok((content, file_path_str))
                })
                .collect();
            file_entries
        })
        .collect::<Result<Vec<_>>>()?
        .into_iter()
        .flatten()
        .collect();

View on GitHub (pinned to 668b1b85e0)