{"record":{"id":"756b3dce5959101c","repo":"facebook/relay","slug":"previous-validation-passes-ensured-this-exists","errorCode":null,"errorMessage":"Previous validation passes ensured this exists.","messagePattern":"Previous validation passes ensured this exists\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs","lineNumber":130,"sourceCode":"    fn new(\n        program: &'program Program,\n        pipeline: ResolversPipeline,\n        enable_shadow_resolvers: bool,\n    ) -> Self {\n        Self {\n            program,\n            pipeline,\n            enable_shadow_resolvers,\n            errors: Default::default(),\n        }\n    }\n\n    fn transformed_field(&self, field: &impl IrField) -> Option<Selection> {\n        RelayResolverFieldMetadata::find(field.directives()).map(|field_metadata| {\n            let fragment_definition = field_metadata.fragment_name.map(|fragment_name| {\n                self.program\n                    .fragment(fragment_name)\n                    .expect(\"Previous validation passes ensured this exists.\")\n            });\n\n            let (fragment_arguments, field_arguments) =\n                field.arguments().iter().cloned().partition(|arg| {\n                    if let Some(fragment_definition) = fragment_definition {\n                        fragment_definition\n                            .variable_definitions\n                            .named(VariableName(arg.name.item.0))\n                            .is_some()\n                    } else {\n                        false\n                    }\n                });\n\n            let resolver_metadata = RelayResolverMetadata {\n                import_path: field_metadata.import_path,\n                import_name: field_metadata.import_name,\n                field_alias: field.alias().map(|field_alias| field_alias.item),","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs#L112-L148","documentation":"In spread_transform's transformed_field, a resolver field's metadata carries a fragment_name, so the program must contain a fragment definition with that name. The expect asserts that previous validation passes guaranteed it exists; when lookup fails, the compiled program is missing a referenced fragment. This signals the fragment was deleted, renamed, or never defined while the resolver field still references it.","triggerScenarios":"transform_scalar_field or transform_linked_field processes a @relay_resolver field whose metadata fragment_name points to a fragment not present in self.program — e.g. the fragment was removed from the document but the resolver directive still references it, or the program passed to the transform excludes the file defining it.","commonSituations":"Deleting or renaming a fragment referenced by @relay_resolver(fragment_name: ...) without updating the resolver; compiler configured with a partial file list so the defining file isn't included; stale incremental cache after refactors.","solutions":["Define the fragment named in the @relay_resolver's fragment_name argument, or update the directive to an existing fragment name.","Include all files containing relay resolver fragments in the compiler's document list (check the include globs in relay.config).","Clear incremental compiler state/caches and rebuild to drop stale program artifacts.","Run schema/fragment name validation before the spread transform to catch dangling references with a better message."],"exampleFix":"// before\n@relay_resolver(import_path: \"UserNameResolver\", fragment_name: \"UserNameResolverFragment\") // fragment deleted\n// after\nfragment UserNameResolverFragment on User { name } // define the referenced fragment","handlingStrategy":"validation","validationCode":"// Before running the spread transform, verify all resolver fragment references resolve:\nfor resolver_directive in all_relay_resolver_directives(&documents) {\n    let name = resolver_directive.arg(\"fragment_name\").to_string();\n    assert!(program.fragment(name).is_some(), \"fragment {} referenced by @relay_resolver not found in program\", name);\n}","typeGuard":"fn resolver_fragments_exist(program: &Program) -> bool {\n    program.fragments().all(|f| {\n        RelayResolverFieldMetadata::find_in(f.selections_directives())\n            .and_then(|m| m.fragment_name)\n            .map(|name| program.fragment(name).is_some())\n            .unwrap_or(true)\n    })\n}","tryCatchPattern":"// Panics abort compilation; validate program completeness first:\nif !resolver_fragments_exist(&program) {\n    return Err(anyhow!(\"@relay_resolver references a fragment missing from the compiled program\"));\n}\nlet output = transformed_field(&field);","preventionTips":["Never delete or rename a fragment without grepping @relay_resolver(fragment_name:) references","Verify relay.config include globs cover every file defining resolver fragments","Clear incremental compiler caches after large refactors","Add a pre-transform validation pass that reports dangling fragment_name references as diagnostics"],"tags":["relay","graphql","compiler-transform","panic","missing-fragment"],"backgroundTag":"missing-fragment-definition","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}