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
- Read the printed diagnostics under 'Failed to build schema:' — they name the offending definitions and locations.
- Fix invalid SDL in the reported schema file (syntax, unknown types/directives).
- De-duplicate matched files: make glob patterns disjoint (don't combine '*.graphql' and '**/*.graphql' over the same tree).
- 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
- Keep glob patterns disjoint so no file is included twice.
- Validate combined SDL (e.g. via build_schema in tests) on every schema change.
- Define each type/directive in exactly one file.
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
- {diagnostics}
- BabelPluginRelay: Expected exactly one definition per graphq
- BabelPluginRelay: Expected a fragment, mutation, query, or s
- GraphQL operations and fragments must contain names
- BabelPluginRelay: Substitutions are not allowed in graphql f
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/304de3789799b298.
Report an issue: GitHub.