facebook/relay · error
Expected parent type
Error message
Expected parent type
What it means
This panic fires in Relay compiler's relay_resolvers transform when a field's parent type is missing from the schema while generating a local @relay_resolver name/type. The schema invariant that every field has a parent type was violated, so the transform cannot derive the resolver's parent type name and aborts. It guards a Rust Option returned by schema lookups, meaning the schema was built incompletely or the transform ran on a field not attached to a type.
Source
Thrown at compiler/crates/relay-transforms/src/relay_resolvers.rs:209
pub resolver_type: ResolverSchemaGenType,
pub return_fragment: Option<WithLocation<FragmentDefinitionName>>,
}
associated_data_impl!(RelayResolverMetadata);
impl RelayResolverMetadata {
pub fn field<'schema>(&self, schema: &'schema SDLSchema) -> &'schema Field {
schema.field(self.field_id)
}
pub fn field_name(&self, schema: &SDLSchema) -> StringKey {
self.field(schema).name.item
}
pub fn field_parent_type_name(&self, schema: &SDLSchema) -> StringKey {
let parent_type = self
.field(schema)
.parent_type
.expect("Expected parent type");
match parent_type {
Type::Interface(interface_id) => schema.interface(interface_id).name.item.0,
Type::Object(object_id) => schema.object(object_id).name.item.0,
_ => panic!("Unexpected parent type for resolver."),
}
}
pub fn generate_local_resolver_name(&self, schema: &SDLSchema) -> StringKey {
resolver_import_alias(self.field_parent_type_name(schema), self.field_name(schema))
}
pub fn generate_local_resolver_type_name(&self, schema: &SDLSchema) -> StringKey {
resolver_type_import_alias(self.field_parent_type_name(schema), self.field_name(schema))
}
}
View on GitHub (pinned to 668b1b85e0)
Solutions
- Inspect the schema: ensure the field's parent type (object/interface) is registered in SDLSchema before running the relay_resolvers transform.
- Rebuild the schema through the normal CompilerState/parse pipeline instead of manual construction so parent_type is always populated.
- Check whether a custom transform earlier in the pipeline detached or replaced the field; run transforms in the documented order.
- If constructing schemas in tests, use the test schema helpers rather than hand-rolled schema structs.
Example fix
// before let field = /* manually built field with parent_type: None */; let name = field.parent_type_name(&schema); // panics // after let field = schema.field(parent_object_id, field_name); // schema-resolved, parent_type always set let name = field.parent_type_name(&schema);
Defensive patterns
Strategy: validation
Validate before calling
// Before invoking resolver name generation, assert the parent exists:
if field.parent_type.is_none() {
panic!("field {} has no parent type; schema is incomplete", field.name.item.0);
}
// or resolve via the schema instead:
let parent = field.parent_type.unwrap_or_else(|| Type::Object(schema.objects_len() - 1)); Type guard
fn has_parent_type(field: &Field) -> bool {
field.parent_type.is_some()
} Try / catch
// Rust panics are not catchable by Result; gate the call:
if has_parent_type(&field) {
let name = field.parent_type_name(&schema);
} else {
return Err(anyhow!("resolver field missing parent type"));
} Prevention
- Build schemas only through the standard parse/build pipeline, never by manual struct construction
- Add an assertion test that every field in your test schema has a parent_type
- Run the full compiler (not just one transform) so invariants are established
- Keep transform order matching Relay's documented pipeline
When it happens
Trigger: Calling generate_local_resolver_name or generate_local_resolver_type_name on a field whose parent_type is None — e.g. the field was synthesized outside normal schema construction, the AST-to-IR schema build skipped the parent link, or the resolver transform was run on a hand-constructed SDLSchema fragment missing the parent object/interface entry.
Common situations: Custom compiler pipelines that build/patch SDLSchema programmatically; schema-generation scripts that insert relay_resolver fields without registering the parent type; mid-upgrade states of the Relay compiler where schema construction changed.
Related errors
- Expected field to be defined on concrete type
- Previous validation passes ensured this exists.
- Terser syntax is only supported on non-input objects or inte
- has_root_fragment() returned true
- shadow_return_directive_fragment_name matched the directive
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/e7e140b059c58313.
Report an issue: GitHub.