facebook/relay · error · Error
NormalizationEngine: Expected path for @stream to end in a p
Error message
NormalizationEngine: Expected path for @stream to end in a positive integer index, got `${String(finalPathEntry)}` What it means
@stream payloads are identified by their position in a list; the last segment of the payload's path must be the integer index of the streamed item. Relay parses the final path entry and requires it to be a non-negative integer that round-trips (parseInt equal to the original). If the path ends in anything else (a field name, a string, -1), Relay cannot determine the list position and throws.
Source
Thrown at packages/relay-runtime/store/NormalizationEngine.js:513
const prevIDs = RelayModernRecord.getLinkedRecordIDs(
parentRecord,
storageKey,
);
if (prevIDs == null) {
throw err(
'NormalizationEngine: Expected record `' +
parentID +
'` to have fetched field `' +
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 =View on GitHub (pinned to 668b1b85e0)
Solutions
- Inspect the incremental payload's `path` in your network layer; ensure the final element is the numeric list index
- Fix or replace the middleware/proxy that is rewriting or dropping path segments
- If building payloads in tests, construct path as [...fieldPath, itemIndex] with a real number as the last entry
- Verify the server actually supports @stream/multipart incremental delivery and emits conformant paths
Example fix
// before
{ path: ["node", "comments"] }
// after
{ path: ["node", "comments", 2] } Defensive patterns
Strategy: validation
Validate before calling
const last = payload.path[payload.path.length - 1];
if (typeof last !== 'number' || !Number.isInteger(last) || last < 0) {
throw new Error(`Invalid @stream path terminator: ${String(last)}`);
} Type guard
function hasNumericIndexPath(p: unknown): p is (string | number)[] {
return Array.isArray(p) && typeof p[p.length - 1] === 'number' && Number.isInteger(p[p.length - 1]);
} Prevention
- Validate incremental payload shape (label/path/id) in your network layer middleware
- Avoid proxies that rewrite incremental delivery paths
- Write conformant mock payloads in tests with numeric final path entries
When it happens
Trigger: Normalizing a @stream incremental payload whose `path` array does not end in a numeric index — e.g. a malformed incremental response from the server, a network layer that mangles the incremental path, or a custom router/gateway rewriting paths (string indices like "01" would also fail since parseInt yields 1 !== "01").
Common situations: Proxy or cache layers (e.g. persisted-query gateways, Cloudflare workers) re-serializing incremental delivery payloads, custom RelayNetwork implementations that build paths incorrectly, or testing harnesses fabricating incremental payloads with wrong paths.
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}
- NormalizationEngine: Expected record `${parentID}` to have f
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/2dfdb178011265c1.
Report an issue: GitHub.