facebook/relay · error

Expected field backing a Client Edge to be a Relay Resolver.

Error message

Expected field backing a Client Edge to be a Relay Resolver. {field:?}

What it means

In the client edge build path for scalar-backed fields, the compiler looks up Relay Resolver metadata (@relay_resolver-style directives) on the scalar field backing a client edge. If the field is a ScalarField but carries no resolver metadata, the compiler cannot treat it as a client edge backing field and panics, printing the field.

Source

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

    }

    fn build_reader_client_edge(
        &mut self,
        context: &mut ContextualMetadata,
        client_edge_metadata: &ClientEdgeMetadata<'_>,
        required_metadata: Option<RequiredMetadataDirective>,
        catch_metadata: Option<CatchMetadataDirective>,
    ) -> Primitive {
        context.has_client_edges = true;
        let backing_field = match &client_edge_metadata.backing_field {
            Selection::FragmentSpread(fragment_spread) => {
                self.build_fragment_spread(fragment_spread)
            }
            Selection::ScalarField(field) => {
                if let Some(resolver_metadata) = RelayResolverMetadata::find(&field.directives) {
                    self.build_scalar_backed_resolver_field(context, field, resolver_metadata)
                } else {
                    panic!("Expected field backing a Client Edge to be a Relay Resolver. {field:?}")
                }
            }
            _ => panic!(
                "Expected Client Edge backing field to be a Relay Resolver. {:?}",
                client_edge_metadata.backing_field
            ),
        };

        let selections_item = if required_metadata.is_none() {
            self.build_linked_field(context, client_edge_metadata.linked_field)
        } else {
            let next_directives = client_edge_metadata
                .linked_field
                .directives
                .iter()
                .filter(|directive| {
                    directive.name.item != RequiredMetadataDirective::directive_name()
                })

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Add the Relay Resolver directive (e.g. @relay_resolver with root_fragment_name) to the backing scalar field.
  2. If the field is not a resolver, change the client edge to point at the correct resolver-backed field.
  3. Check that no custom transform strips the resolver directives before codegen.
  4. Validate the client schema extension with the relay compiler's schema checks before compiling documents.

Example fix

// before
extend type Query { myEdge: MyType @clientEdge }

// after
extend type Query { myEdge: MyType @relay_resolver(root_fragment_name: "MyEdgeFragment") @clientEdge }
Defensive patterns

Strategy: validation

Validate before calling

function validateResolverDirective(field) {
  const hasResolver = field.directives?.some(d =>
    ['relay_resolver', 'relayResolver'].includes(d.name.value));
  if (!hasResolver) {
    throw new Error('Field ' + field.name.value + ' backs a client edge but has no @relay_resolver directive');
  }
}

Type guard

function isRelayResolverField(field) {
  return field?.directives?.some(d => d.name.value === 'relay_resolver') === true;
}

Try / catch

try {
  compile();
} catch (e) {
  if (String(e).includes('backing a Client Edge to be a Relay Resolver')) {
    console.error('Add @relay_resolver to the backing field:', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: A client edge whose backing scalar field lacks RelayResolverMetadata directives — e.g. the @relay_resolver directive was removed, renamed, or never added while the field is still wired as a client edge backing field.

Common situations: Removing a resolver directive during refactoring while leaving client edge wiring; schema extensions generated by older tooling without resolver annotations; directives stripped by an earlier transform.

Related errors


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