facebook/relay · error · Error
NormalizationEngine: Expected @stream field `${field.name}`
Error message
NormalizationEngine: Expected @stream field `${field.name}` to have a __typename. What it means
To normalize a streamed item Relay must know its concrete type. It uses the field's concreteType (from a inline fragment/typed field in the query) when available, otherwise it falls back to the `__typename` in the streamed item's data. If neither yields a string, Relay cannot create a normalization selector and throws. This usually means the server omitted `__typename` from the streamed item or the query selected the field without a type.
Source
Thrown at packages/relay-runtime/store/NormalizationEngine.js:523
field.name +
'` with @stream.',
);
}
const finalPathEntry = path[path.length - 1];
const itemIndex = parseInt(finalPathEntry, 10);
if (itemIndex !== finalPathEntry || itemIndex < 0) {
throw err(
'NormalizationEngine: Expected path for @stream to end in a ' +
'positive integer index, got `' +
String(finalPathEntry) +
'`',
);
}
const typeName = field.concreteType ?? (data as $FlowFixMe).__typename;
if (typeof typeName !== 'string') {
throw err(
'NormalizationEngine: Expected @stream field `' +
field.name +
'` to have a __typename.',
);
}
const getDataID = this._options.getDataID;
const itemID =
(typeof getDataID === 'function'
? getDataID(data as $FlowFixMe, typeName)
: null) ??
prevIDs?.[itemIndex] ??
generateClientID(parentID, storageKey, itemIndex);
if (typeof itemID !== 'string') {
throw err(
'NormalizationEngine: Expected id of elements of field `' +
storageKey +
'` to be strings.',View on GitHub (pinned to 668b1b85e0)
Solutions
- Add `__typename` to the selection set of the @stream field in your query
- Fix the server/gateway to include __typename in streamed incremental payloads
- Remove any middleware that deletes __typename from response data
- If the type is statically known, ensure the compiled query provides concreteType for the field
Example fix
// before
fragment F on Node { comments @stream { id text } }
// after
fragment F on Node { comments @stream { __typename id text } } Defensive patterns
Strategy: validation
Validate before calling
if (field.concreteType == null && typeof payload.data?.__typename !== 'string') {
throw new Error(`@stream field ${field.name} missing __typename`);
} Type guard
function hasTypename(d: unknown): d is { __typename: string } {
return typeof d === 'object' && d !== null && typeof (d as any).__typename === 'string';
} Prevention
- Always select __typename on @stream fields
- Never strip __typename in response middleware
- Ensure the server echoes __typename in incremental payloads
When it happens
Trigger: Normalizing a @stream item where field.concreteType is undefined AND the item data lacks a string `__typename` — e.g. the server doesn't echo __typename for streamed list items, or the query selects the streamed field without __typename and without a concrete type.
Common situations: Custom/older GraphQL servers that don't add __typename to incremental payloads, hand-rolled mock servers in tests forgetting __typename, or stripping __typename in a network-layer middleware (e.g. after apollo-link-style normalization).
Related errors
- NormalizationEngine: Expected incremental response to have `
- NormalizationEngine: Expected @stream to be used on a plural
- NormalizationEngine: Expected the GraphQL @stream payload `d
- NormalizationEngine: Expected the parent record `${parentID}
- BabelPluginRelay: Expected exactly one definition per graphq
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/6725c168330d1050.
Report an issue: GitHub.