facebook/relay · error
Expected a scalar field.
Error message
Expected a scalar field.
What it means
When a type-discriminating inline fragment (e.g. from @match or a `typename` discriminator pattern) is processed, the compiler expects its single selection to be a scalar field that serves as the type discriminator. If the first selection is not a scalar field, it panics because no scalar field exists to build the discriminator from.
Source
Thrown at compiler/crates/relay-codegen/src/build_ast.rs:2399
// This means we have to handle two cases:
// - The inline fragment only contains a TypeDiscriminator with the same
// abstractKey: replace the Fragment w the Discriminator
// - The inline fragment contains other selections: return all the selections
// minus any Discriminators w the same key
let has_type_discriminator = inline_frag
.selections
.iter()
.any(is_type_discriminator_selection);
if has_type_discriminator {
if inline_frag.selections.len() == 1 {
return self.build_type_discriminator(
if let Selection::ScalarField(field) =
&inline_frag.selections[0]
{
field
} else {
panic!("Expected a scalar field.")
},
);
} else {
let selections = self.build_selections(
context,
inline_frag.selections.iter().filter(|selection| {
!is_type_discriminator_selection(selection)
}),
);
return Primitive::Key(self.object(object! {
kind: Primitive::String(CODEGEN_CONSTANTS.inline_fragment),
selections: selections,
type_: Primitive::String(
self.schema.get_type_name(type_condition),
),
abstract_key: Primitive::String(
generate_abstract_type_refinement_key(
self.schema,View on GitHub (pinned to 668b1b85e0)
Solutions
- Ensure the discriminating inline fragment's first (and ideally only) selection is a scalar field such as `__typename` or the resolver payload field.
- Remove extra selections from the discriminator fragment or move them into a sibling fragment.
- Disable/review custom transforms that reorder or inject selections before build_ast.
- Regenerate the document instead of hand-editing compiled/output IR.
Example fix
// before
... on Note { createdAt viewer { name } }
// after
... on Note { note } // note is the scalar resolver payload field, first selection Defensive patterns
Strategy: validation
Validate before calling
function validateDiscriminatorFragment(inlineFrag) {
const first = inlineFrag.selections?.[0];
if (!first || first.kind !== 'Field' || first.selections) {
throw new Error('Type discriminator inline fragment must start with a scalar field');
}
} Type guard
function startsWithScalarField(inlineFrag) {
const first = inlineFrag?.selections?.[0];
return first != null && first.kind === 'Field' &&
(!first.selectionSet && !first.selections);
} Try / catch
try {
compile();
} catch (e) {
if (String(e).includes('Expected a scalar field')) {
console.error('Discriminator inline fragment must have a scalar field as its first selection.');
} else throw e;
} Prevention
- Put the scalar payload/__typename field first in discriminator fragments
- Avoid hand-editing transformed IR
- Review custom transforms that reorder selections
- Keep @match/@module fragments to a single scalar selection
When it happens
Trigger: Compiling an inline fragment whose selections[0] is not a ScalarField — e.g. a linked field, fragment spread, or another inline fragment — in a context where Relay builds a type discriminator (typename-based branching).
Common situations: Hand-written or transformed documents where @match/module fragments have multiple or non-scalar first selections; custom transforms reordering selections; editing generated code so the discriminator field is no longer first.
Related errors
- unexpected value for @defer if argument: {other:?}
- unexpected value for @stream if argument: {other:?}
- Unexpected custom directives: {:#?}
- Expected filters_arg to have been previously validated.
- expected to find a supported argument as checked before
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/8d10f14057cf98fc.
Report an issue: GitHub.