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

  1. 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.
  2. Verify the pass that inserts @rootFragment definitions runs before the spread transform.
  3. Check that earlier pruning/dead-code transforms are not removing the resolver's root fragment.
  4. 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

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


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