facebook/relay · error
Expect to have a fragment node.
Error message
Expect to have a fragment node.
What it means
Immediately after unwrapping the fragment name, the spread transform looks the fragment up in the program via self.program.fragment(...) and expects the fragment definition node to exist. A missing fragment means the @rootFragment/@returnFragment target was not added to the program before this transform, which the code treats as a compiler bug ("Expect to have a fragment node.").
Source
Thrown at compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs:166
field_alias: field.alias().map(|field_alias| field_alias.item),
field_path: field_metadata.field_path,
field_id: field.definition().item,
field_arguments,
fragment_arguments: fragment_arguments.clone(),
live: field_metadata.live,
output_type_info: field_metadata.output_type_info.clone(),
fragment_data_injection_mode: field_metadata
.fragment_data_injection_mode
.as_ref()
.map(|injection_mode| {
(
self.program
.fragment(
field_metadata
.fragment_name
.expect("Expected to have a fragment name."),
)
.expect("Expect to have a fragment node.")
.name,
*injection_mode,
)
}),
type_confirmed: field_metadata.type_confirmed,
resolver_type: field_metadata.resolver_type,
return_fragment: field_metadata.return_fragment,
};
let mut new_directives: Vec<Directive> = vec![resolver_metadata.into()];
for directive in field.directives() {
if directive.name.item != RelayResolverFieldMetadata::directive_name() {
new_directives.push(directive.clone())
}
}
if let Some(fragment_definition) = fragment_definition {
Selection::FragmentSpread(Arc::new(FragmentSpread {View on GitHub (pinned to 668b1b85e0)
Solutions
- Run the transform on the full program (all documents) so the root fragment definition is present, not per-file with the fragment in another module.
- Verify the pass that inserts @rootFragment definitions runs before the spread transform.
- Check that earlier pruning/dead-code transforms are not removing the resolver's root fragment.
- File a relay compiler bug with a minimal repro if the standard pipeline panics.
Defensive patterns
Strategy: validation
Validate before calling
if self.program.fragment(name).is_none() {
panic!("fragment `{name}` referenced by resolver metadata is not in the program");
} Type guard
fn fragment_in_program(program: &Program, name: &str) -> bool { program.fragment(name).is_some() } Try / catch
let Some(fragment) = self.program.fragment(name) else {
return Err(Diagnostic::error(format!("missing fragment {name}")));
}; Prevention
- Compile whole programs, not isolated documents, for resolver flows.
- Do not prune fragments before the spread transform.
- Verify @rootFragment insertion passes run first.
When it happens
Trigger: field_metadata.fragment_name points at a fragment that was never inserted into the Program's fragment map — e.g. the root-fragment insertion pass did not run, the fragment was pruned by an earlier dead-fragment elimination, or the name is misspelled by the producing pass.
Common situations: Custom transform ordering in a bespoke compiler binary; fragments defined only in the shadow AST but not the main program; running transforms on partial programs (e.g. per-file compilation where the root fragment lives in another file).
Related errors
- Expected to have a fragment name.
- shadow resolver with @returnFragment must declare a @rootFra
- Expect fragment to exist.
- useRefetchableFragmentNode: Unexpected action type
- commitMutation: Expected mutation operation
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/fb120cf2c8032fbf.
Report an issue: GitHub.