facebook/relay · error

Failed to build schema: {}

Error message

Failed to build schema:
{}

What it means

After collecting schema file contents, load_schema builds an SDLSchema from the parsed sources. If schema building produces GraphQL diagnostics (duplicate type definitions, invalid SDL, unknown directives/types, syntax errors in SDL files), they are printed via DiagnosticPrinter and wrapped as 'Failed to build schema'. The individual files parsed as text but the combined type-system is invalid.

Source

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

    let schema_sdls: Vec<(String, SourceLocationKey)> = schema_files
        .into_iter()
        .map(|(content, file_path)| {
            let source_key = SourceLocationKey::standalone(&file_path);
            (content, source_key)
        })
        .collect();

    let schema = schema::build_schema_with_extensions_parallel::<_, &str>(
        &schema_sdls
            .iter()
            .map(|(content, key)| (content.as_str(), *key))
            .collect::<Vec<_>>(),
        &[],
    )
    .map_err(|diagnostics| {
        let printer =
            DiagnosticPrinter::new(|key: SourceLocationKey| source_map.get(&key).cloned());
        anyhow!(
            "Failed to build schema:\n{}",
            printer.diagnostics_to_string(&diagnostics)
        )
    })?;

    Ok(Arc::new(schema))
}

/// Compare 2 GraphQL executable definitions belonging to the same schema, by subtracting doc2's normalized selection
/// set from doc1's. Normalized selection set is the minimal set of (linked/scalar) field and argument combo that
/// is selected by the executable, considering the field's type condition enforced by its {} enclosures. Comparison
/// is assisted by typing information from the schema, passed as a comma separated list of paths.
///
/// # Returns (score, message)
/// * `score` - numerical score in [0.0, 1.0], where 0 means doc1 is disjointed from doc2, and 1 means doc1 is
///   a subset of doc2
/// * `message` - details of relative complement of doc1 with respect to doc2, aka. doc1 - doc2
pub fn compare(schema_paths: Vec<String>, doc1: &str, doc2: &str) -> Result<(f64, String)> {

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Read the printed diagnostics under 'Failed to build schema:' — they name the offending definitions and locations.
  2. Fix invalid SDL in the reported schema file (syntax, unknown types/directives).
  3. De-duplicate matched files: make glob patterns disjoint (don't combine '*.graphql' and '**/*.graphql' over the same tree).
  4. Split schema content so each type/directive is defined exactly once across all matched files.

Example fix

// before
load_schema(vec!["schemas/*.graphql".into(), "schemas/**/*.graphql".into()])?; // dup files -> duplicate types
// after
load_schema(vec!["schemas/**/*.graphql".into()])?;
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect overlapping globs that would double-load the same file
fn has_duplicate_matches(patterns: &[String]) -> bool {
    let mut seen = std::collections::HashSet::new();
    patterns.iter().any(|p| {
        glob::glob(p).unwrap().filter_map(Result::ok).any(|path| !seen.insert(path))
    })
}
assert!(!has_duplicate_matches(&schema_paths));

Try / catch

let schema = load_schema(paths.clone()).map_err(|e| {
    if e.to_string().starts_with("Failed to build schema") {
        eprintln!("{e}"); // includes DiagnosticPrinter output with file locations
        anyhow!("fix SDL per diagnostics above")
    } else { e }
});

Prevention

When it happens

Trigger: Calling load_schema/compare where the union of matched SDL files fails schema validation — e.g. two globs match overlapping files causing duplicate type definitions, or a schema file contains invalid SDL.

Common situations: Glob patterns ('schemas/*.graphql', 'schemas/**/*.graphql') matching the same file twice; merging generated and hand-written schema files that redefine types; a schema file edited with invalid SDL.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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