facebook/relay · error
Expected Client Edge backing field to be a Relay Resolver. {
Error message
Expected Client Edge backing field to be a Relay Resolver. {:?} What it means
When reading directives of a client edge backing field, the compiler only accepts ScalarField or InlineFragment selections (both can carry Relay Resolver metadata). Any other selection kind (LinkedField, FragmentSpread at this stage, etc.) reaching this match means the backing field is not a Relay Resolver-backed field, so it panics with the selection dumped.
Source
Thrown at compiler/crates/relay-codegen/src/build_ast.rs:2061
if backing_field_primitives.len() != 1 {
panic!(
"Expected client edge backing field to be transformed into exactly one primitive."
)
}
let backing_field = backing_field_primitives.into_iter().next().unwrap();
let selections_item = self.build_linked_field(context, client_edge_metadata.linked_field);
match &client_edge_metadata.metadata_directive {
ClientEdgeMetadataDirective::ClientObject {
model_resolvers, ..
} => {
let field_directives = match &client_edge_metadata.backing_field {
Selection::ScalarField(field) => Some(&field.directives),
// Although the reader checks for FragmentSpreads on the backing field, the normalization
// transforms inline the fragment spread so we match an InlineFragment here
Selection::InlineFragment(inline_frag) => Some(&inline_frag.directives),
_ => panic!(
"Expected Client Edge backing field to be a Relay Resolver. {:?}",
client_edge_metadata.backing_field
),
};
let client_edge_model_resolvers = field_directives.and_then(|field_directives| {
let resolver_metadata = RelayResolverMetadata::find(field_directives).unwrap();
let is_weak_resolver = matches!(
resolver_metadata.output_type_info,
ResolverOutputTypeInfo::Composite(_)
);
let model_resolver_primitives = if !is_weak_resolver {
self.build_client_edge_model_resolvers(model_resolvers, resolver_metadata)
} else {
vec![]
};
if model_resolver_primitives.is_empty() {
None
} else {View on GitHub (pinned to 668b1b85e0)
Solutions
- Make the client edge backing field a Relay Resolver scalar field (or an inline fragment that normalizes to one).
- Confirm the normalization transforms that inline fragment spreads ran before codegen; align compiler version with your transform config.
- Check RelayResolverMetadata is attached via @relay_resolver / RescriptRelay resolver directives on the backing field.
- Dump the normalized IR to verify which selection kind the backing field became.
Example fix
// before: backing field is a linked field
extend type Query { items: [Item] @clientEdge }
// after: backing field is a resolver scalar
extend type Query { itemResolver: Item @relay_resolver(root_fragment_name: "ItemResolverFragment") @clientEdge } Defensive patterns
Strategy: type-guard
Validate before calling
function validateClientEdgeBacking(selection) {
const ok = selection.kind === 'ScalarField' || selection.kind === 'InlineFragment';
if (!ok) {
throw new Error('Client edge backing field must be a scalar or inline fragment, got ' + selection.kind);
}
} Type guard
function isResolverBackableSelection(s) {
return s != null && (s.kind === 'ScalarField' || s.kind === 'InlineFragment');
} Try / catch
try {
compile();
} catch (e) {
if (String(e).includes('Client Edge backing field to be a Relay Resolver')) {
console.error('Backing field selection kind not resolver-compatible:', e.message);
} else throw e;
} Prevention
- Define client edges only over Relay resolver scalar fields
- Confirm normalization transforms inline backing spreads
- Inspect normalized IR when changing client edge definitions
- Keep compiler/tooling versions aligned
When it happens
Trigger: Compiling a client edge whose backing field is a Selection::LinkedField or any selection other than a scalar field / inline fragment after normalization transforms.
Common situations: Defining a client edge over a linked (object) field instead of a resolver scalar; transform pipeline differences where the backing fragment spread was not inlined to an InlineFragment; hand-edited client schema extensions.
Related errors
- Expected client edge backing field to be transformed into ex
- Expected field backing a Client Edge to be a Relay Resolver.
- unexpected value for @defer if argument: {other:?}
- unexpected value for @stream if argument: {other:?}
- Unexpected custom directives: {:#?}
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/0a6d02516bfe0a2b.
Report an issue: GitHub.