facebook/relay · error
Previous validation passes ensured this exists.
Error message
Previous validation passes ensured this exists.
What it means
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.
Source
Thrown at compiler/crates/relay-transforms/src/relay_resolvers/spread_transform.rs:130
fn new(
program: &'program Program,
pipeline: ResolversPipeline,
enable_shadow_resolvers: bool,
) -> Self {
Self {
program,
pipeline,
enable_shadow_resolvers,
errors: Default::default(),
}
}
fn transformed_field(&self, field: &impl IrField) -> Option<Selection> {
RelayResolverFieldMetadata::find(field.directives()).map(|field_metadata| {
let fragment_definition = field_metadata.fragment_name.map(|fragment_name| {
self.program
.fragment(fragment_name)
.expect("Previous validation passes ensured this exists.")
});
let (fragment_arguments, field_arguments) =
field.arguments().iter().cloned().partition(|arg| {
if let Some(fragment_definition) = fragment_definition {
fragment_definition
.variable_definitions
.named(VariableName(arg.name.item.0))
.is_some()
} else {
false
}
});
let resolver_metadata = RelayResolverMetadata {
import_path: field_metadata.import_path,
import_name: field_metadata.import_name,
field_alias: field.alias().map(|field_alias| field_alias.item),View on GitHub (pinned to 668b1b85e0)
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.
Example fix
// before
@relay_resolver(import_path: "UserNameResolver", fragment_name: "UserNameResolverFragment") // fragment deleted
// after
fragment UserNameResolverFragment on User { name } // define the referenced fragment Defensive patterns
Strategy: validation
Validate before calling
// Before running the spread transform, verify all resolver fragment references resolve:
for resolver_directive in all_relay_resolver_directives(&documents) {
let name = resolver_directive.arg("fragment_name").to_string();
assert!(program.fragment(name).is_some(), "fragment {} referenced by @relay_resolver not found in program", name);
} Type guard
fn resolver_fragments_exist(program: &Program) -> bool {
program.fragments().all(|f| {
RelayResolverFieldMetadata::find_in(f.selections_directives())
.and_then(|m| m.fragment_name)
.map(|name| program.fragment(name).is_some())
.unwrap_or(true)
})
} Try / catch
// Panics abort compilation; validate program completeness first:
if !resolver_fragments_exist(&program) {
return Err(anyhow!("@relay_resolver references a fragment missing from the compiled program"));
}
let output = transformed_field(&field); Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Expected parent type
- Expected field to be defined on concrete type
- has_root_fragment() returned true
- shadow_return_directive_fragment_name matched the directive
- BabelPluginRelay: Expected exactly one definition per graphq
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/756b3dce5959101c.
Report an issue: GitHub.