{"record":{"id":"fb120cf2c8032fbf","repo":"facebook/relay","slug":"expect-to-have-a-fragment-node","errorCode":null,"errorMessage":"Expect to have a fragment node.","messagePattern":"Expect to have a fragment node\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs","lineNumber":166,"sourceCode":"                field_alias: field.alias().map(|field_alias| field_alias.item),\n                field_path: field_metadata.field_path,\n                field_id: field.definition().item,\n                field_arguments,\n                fragment_arguments: fragment_arguments.clone(),\n                live: field_metadata.live,\n                output_type_info: field_metadata.output_type_info.clone(),\n                fragment_data_injection_mode: field_metadata\n                    .fragment_data_injection_mode\n                    .as_ref()\n                    .map(|injection_mode| {\n                        (\n                            self.program\n                                .fragment(\n                                    field_metadata\n                                        .fragment_name\n                                        .expect(\"Expected to have a fragment name.\"),\n                                )\n                                .expect(\"Expect to have a fragment node.\")\n                                .name,\n                            *injection_mode,\n                        )\n                    }),\n                type_confirmed: field_metadata.type_confirmed,\n                resolver_type: field_metadata.resolver_type,\n                return_fragment: field_metadata.return_fragment,\n            };\n\n            let mut new_directives: Vec<Directive> = vec![resolver_metadata.into()];\n\n            for directive in field.directives() {\n                if directive.name.item != RelayResolverFieldMetadata::directive_name() {\n                    new_directives.push(directive.clone())\n                }\n            }\n            if let Some(fragment_definition) = fragment_definition {\n                Selection::FragmentSpread(Arc::new(FragmentSpread {","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs#L148-L184","documentation":"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.\").","triggerScenarios":"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.","commonSituations":"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).","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if self.program.fragment(name).is_none() {\n    panic!(\"fragment `{name}` referenced by resolver metadata is not in the program\");\n}","typeGuard":"fn fragment_in_program(program: &Program, name: &str) -> bool { program.fragment(name).is_some() }","tryCatchPattern":"let Some(fragment) = self.program.fragment(name) else {\n    return Err(Diagnostic::error(format!(\"missing fragment {name}\")));\n};","preventionTips":["Compile whole programs, not isolated documents, for resolver flows.","Do not prune fragments before the spread transform.","Verify @rootFragment insertion passes run first."],"tags":["relay-compiler","missing-fragment","internal-invariant"],"backgroundTag":"relay-compiler-missing-fragment","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}