{"record":{"id":"2f49f4b151e3e0a3","repo":"facebook/relay","slug":"normalizationengine-expected-the-graphql-stream","errorCode":null,"errorMessage":"NormalizationEngine: Expected the GraphQL @stream payload `data` value to be an object.","messagePattern":"NormalizationEngine: Expected the GraphQL @stream payload `data` value to be an object\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/store/NormalizationEngine.js","lineNumber":478,"sourceCode":"\n  _normalizeStreamItem(\n    response: GraphQLResponseWithData,\n    parentID: string,\n    field: NormalizationLinkedField,\n    variables: Variables,\n    path: ReadonlyArray<unknown>,\n    normalizationPath: ReadonlyArray<string>,\n  ): {\n    fieldPayloads: Array<HandleFieldPayload>,\n    itemID: string,\n    itemIndex: number,\n    prevIDs: Array<?string>,\n    relayPayload: RelayResponsePayload,\n    storageKey: string,\n  } {\n    const {data} = response;\n    if (typeof data !== 'object') {\n      throw err(\n        'NormalizationEngine: Expected the GraphQL @stream payload `data` ' +\n          'value to be an object.',\n      );\n    }\n    const responseKey = field.alias ?? field.name;\n    const storageKey = getStorageKey(field, variables);\n\n    const parentEntry = this._parentRecords.get(parentID);\n    if (parentEntry == null) {\n      throw err(\n        'NormalizationEngine: Expected the parent record `' +\n          parentID +\n          '` for @stream data to exist.',\n      );\n    }\n    const {fieldPayloads, record: parentRecord} = parentEntry;\n\n    const prevIDs = RelayModernRecord.getLinkedRecordIDs(","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/store/NormalizationEngine.js#L460-L496","documentation":"In _normalizeStreamItem, Relay destructures `data` from the incremental @stream response and requires it to be an object (the streamed item's fields). If `data` is a primitive, array-unexpectedly-null, or undefined (anything with typeof !== 'object'), Relay cannot normalize the item and throws.","triggerScenarios":"A @stream incremental payload arrives whose `data` value is not an object — e.g. the server sends `data: null` for an errored stream item, a scalar, or the network layer mangles the multipart part so data is missing.","commonSituations":"Servers sending null data alongside errors on streamed items; custom network layers parsing multipart chunks incorrectly (JSON fragments concatenated or truncated); proxies/transcoders altering incremental payloads.","solutions":["Inspect the raw streamed payload and confirm `data` is an object; if the server sends null with errors, handle/inspect the `errors` field instead of normalizing.","Fix the server so each @stream part carries an object `data` (or omit the part when there is no data).","Check the network layer's multipart parsing — ensure each chunk is parsed as complete JSON before being passed to the Relay environment.","Check whether a proxy or fetch wrapper transforms the response body and strips/replaces `data`."],"exampleFix":"// before\nhandleNextChunk(rawPart); // data may be null\n// after\nif (rawPart.data != null && typeof rawPart.data === 'object') {\n  handleNextChunk(rawPart);\n} else {\n  handleError(rawPart.errors);\n}","handlingStrategy":"type-guard","validationCode":"function hasObjectData(part) {\n  return part != null && typeof part.data === 'object' && part.data !== null;\n}\nif (!hasObjectData(streamPart)) { /* route to error handling instead of normalizing */ }","typeGuard":"function isObjectPayload(res) {\n  return typeof res === 'object' && res !== null &&\n    'data' in res && typeof res.data === 'object' && res.data !== null;\n}","tryCatchPattern":"try {\n  normalizationEngine.processIncrementalResponse(response);\n} catch (e) {\n  if (String(e.message).includes('@stream payload `data`')) {\n    handleStreamError(response.errors);\n  } else throw e;\n}","preventionTips":["Ensure the server omits or error-handles stream parts instead of sending null data silently.","Parse each multipart chunk as complete JSON before passing it to Relay.","Beware proxies/transformers altering incremental payloads.","Check the `errors` field of a part before normalizing data that may be null."],"tags":["relay","graphql","stream","payload-validation"],"backgroundTag":"malformed-incremental-payload","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}