facebook/relay · error
has_root_fragment() returned true
Error message
has_root_fragment() returned true
What it means
During resolver metadata validation, Relay's shadow transform expects that a field marked as having a root fragment (per has_root_fragment()) always carries a fragment_name in its metadata. The expect unwraps that Option; if absent, an earlier validation pass and the has_root_fragment computation disagreed. This is an internal invariant check, so hitting it indicates corrupted or inconsistently built resolver field metadata.
Source
Thrown at compiler/crates/relay-transforms/src/relay_resolvers/shadow_transform.rs:277
self.errors.push(Diagnostic::error(
ValidationMessage::ReturnFragmentInvalidModuleName {
module_name,
fragment_name: return_fragment.item.0,
},
location,
));
}
// Validate: return fragment must be spread within the root fragment.
//
// The `@returnFragment` placeholder spread is converted into the
// schema-known internal `@__relay_shadow_return` directive at the AST
// rail (before `build_ir`). So we look for that marker directive (keyed
// on the return fragment name), not the original spread, which no longer
// exists by the time we reach IR.
let root_fragment_name = field_metadata
.fragment_name
.expect("has_root_fragment() returned true");
if let Some(root_fragment) = self.program.fragment(root_fragment_name)
&& !selections_contain_shadow_return_marker(
&root_fragment.selections,
return_fragment.item,
)
{
self.errors.push(Diagnostic::error(
ValidationMessage::ReturnFragmentNotSpreadInRootFragment {
return_fragment_name: return_fragment.item,
root_fragment_name,
},
location,
));
}
}
}
View on GitHub (pinned to 668b1b85e0)
Solutions
- Ensure the @relay_resolver directive includes fragment_name (and required arguments) so has_root_fragment and fragment_name agree.
- Re-run the full compiler pipeline from source rather than incremental artifacts so metadata is rebuilt consistently.
- Check custom transforms that construct RelayResolverFieldMetadata and make them set fragment_name whenever the root-fragment flag is true.
- File an issue with the failing document if the directive looks correct — it indicates an internal invariant bug.
Example fix
// before @relay_resolver(import_path: "ImageResolver") // no fragment_name // after @relay_resolver(import_path: "ImageResolver", fragment_name: "ImageResolverFragment", root_fragment_name: "ImageResolverRootFragment")
Defensive patterns
Strategy: validation
Validate before calling
// Pre-check resolver directive metadata coherence before compiling:
if directive.args.get("has_root_fragment") == Some(&Bool(true)) {
assert!(directive.args.contains_key("fragment_name"), "@relay_resolver with root fragment requires fragment_name");
} Type guard
fn metadata_is_coherent(meta: &RelayResolverFieldMetadata) -> bool {
!(meta.has_root_fragment() && meta.fragment_name.is_none())
} Try / catch
// Panics are not catchable as errors; pre-validate:
let meta = RelayResolverFieldMetadata::find(directives).ok_or("not a resolver field")?;
if !metadata_is_coherent(&meta) {
return Err(anyhow!("resolver metadata: has_root_fragment set without fragment_name"));
} Prevention
- Always supply fragment_name and root_fragment_name on @relay_resolver directives that use root fragments
- Rebuild from clean state after upgrading Relay so old metadata doesn't linger
- Avoid custom transforms that mutate RelayResolverFieldMetadata flags independently
- If the directive looks correct, report it upstream as a compiler invariant bug
When it happens
Trigger: validate_resolver_metadata processes a field whose RelayResolverFieldMetadata has has_root_fragment()==true but fragment_name==None — e.g. the @relay_resolver directive lacked fragment_name/root-fragment arguments, or custom metadata construction set the flag without the name.
Common situations: Hand-written or partially generated @relay_resolver directives missing the fragment_name argument; a mis-ordered transform pipeline running shadow_transform before metadata validation populates fragment_name; upgrading Relay with older persisted schema metadata.
Related errors
- shadow_return_directive_fragment_name matched the directive
- Expected parent type
- Expected field to be defined on concrete type
- Previous validation passes ensured this exists.
- Expected filters_arg to have been previously validated.
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/43a5f370f7a03491.
Report an issue: GitHub.