facebook/relay · error

Unexpected parent type for resolver.

Error message

Unexpected parent type for resolver.

What it means

When generating the normalization AST for a worker-style relay resolver, the resolver's parent type must be an object or interface. The code unwraps resolver_metadata parent_type with .unwrap() and matches only Interface/Object variants; any other type (scalar, union, enum) hits the panic.

Source

Thrown at compiler/crates/relay-codegen/src/build_ast.rs:1163

    ) -> Primitive {
        let field_name = resolver_metadata.field_name(self.schema);
        // Include both field_arguments and fragment_arguments (see comment
        // in build_normalization_relay_resolver_exec_and_read_time).
        let all_arguments: Vec<_> = resolver_metadata
            .field_arguments
            .iter()
            .chain(resolver_metadata.fragment_arguments.iter())
            .cloned()
            .collect();
        let args = self.build_arguments(&all_arguments);
        let is_output_type = resolver_metadata
            .output_type_info
            .normalization_ast_should_have_is_output_type_true();

        let field_type = match resolver_metadata.field(self.schema).parent_type.unwrap() {
            Type::Interface(interface_id) => self.schema.interface(interface_id).name.item.0,
            Type::Object(object_id) => self.schema.object(object_id).name.item.0,
            _ => panic!("Unexpected parent type for resolver."),
        };

        let variable_name = resolver_metadata.generate_local_resolver_name(self.schema);
        let kind = if resolver_metadata.live {
            CODEGEN_CONSTANTS.relay_live_resolver
        } else {
            CODEGEN_CONSTANTS.relay_resolver
        };
        Primitive::Key(self.object(object! {
            name: Primitive::String(field_name),
            args: match args {
                None => Primitive::SkippableNull,
                Some(key) => Primitive::Key(key),
            },
            kind: Primitive::String(kind),
            storage_key: match args {
                None => Primitive::SkippableNull,
                Some(key) => {

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Move the resolver so its parent type is an object or interface type.
  2. Fix the resolver metadata/parentType declaration so it points at the correct object/interface.
  3. If the parent is legitimately a union, restructure the resolver per fragment or update the compiler to support unions on that path.
  4. Regenerate metadata after schema refactors so parent_type reflects the current schema.

Example fix

// before
union SearchResult = User | Story
extend type SearchResult @relay_resolver(...)
// after: attach resolver to a concrete parent
extend type Query @relay_resolver(name: "searchResolver")
Defensive patterns

Strategy: validation

Validate before calling

fn resolver_parent_type_ok(schema: &Schema, meta: &ResolverMetadata) -> bool {
    matches!(meta.parent_type, Some(Type::Object(_)) | Some(Type::Interface(_)))
}

Type guard

fn is_object_or_interface(t: &Type) -> bool {
    matches!(t, Type::Object(_) | Type::Interface(_))
}

Try / catch

let result = std::panic::catch_unwind(|| build_normalization_relay_resolver(...));
if result.is_err() { report("resolver parent type must be object or interface"); }

Prevention

When it happens

Trigger: build_normalization_relay_resolver_execution_time_for_worker encounters a resolver whose declared parent type is not an object or interface — e.g. a resolver attached to a union, scalar, or with a missing/incorrect parent_type in its metadata.

Common situations: Defining a resolver on a union type where the codegen only supports object/interface parents; stale resolver metadata after refactoring a type from interface to union; misconfigured @relay_resolver parentType value.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/31544c100e5fb64c. Report an issue: GitHub.