{"record":{"id":"e4a70e0e5aae3e34","repo":"facebook/relay","slug":"normalizationengine-expected-incremental-response","errorCode":null,"errorMessage":"NormalizationEngine: Expected incremental response to have `label` and `path` properties.","messagePattern":"NormalizationEngine: Expected incremental response to have `label` and `path` properties\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/store/NormalizationEngine.js","lineNumber":223,"sourceCode":"      pendingModules,\n    };\n  }\n\n  /**\n   * Process an incremental response (@defer chunk or @stream item).\n   * Matches the response to a registered placeholder by label + path.\n   *\n   * Returns null if the response was buffered (no placeholder yet).\n   * Otherwise returns payloads array and pending module Promises.\n   */\n  processIncrementalResponse(\n    response: GraphQLResponseWithData,\n  ): ?NormalizationResult {\n    const label: ?string = response.label;\n    const path: ?ReadonlyArray<string | number> = response.path;\n\n    if (label == null || path == null) {\n      throw err(\n        'NormalizationEngine: Expected incremental response to have ' +\n          '`label` and `path` properties.',\n      );\n    }\n\n    const isDefer = label.indexOf('$defer$') !== -1;\n    const pathKey = isDefer\n      ? path.map(String).join('.')\n      : path.slice(0, -2).map(String).join('.');\n    const key = makeKey(label, pathKey);\n\n    const placeholder = this._placeholders.get(key);\n\n    if (placeholder == null) {\n      // Buffer: response arrived before placeholder was registered\n      let buffer = this._bufferedResponses.get(key);\n      if (buffer == null) {\n        buffer = [];","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/store/NormalizationEngine.js#L205-L241","documentation":"Relay's NormalizationEngine processes incremental (defer/stream) responses and requires each incremental payload to carry `label` and `path`. These identify which deferred fragment and where in the response tree the payload belongs. When an incremental response arrives without either property, Relay cannot route the data into the store and throws immediately.","triggerScenarios":"Calling `processIncrementalResponse` with a `GraphQLResponseWithData` object whose `label` or `path` is null/undefined — typically because a custom network layer split or forwarded the raw multipart payload incorrectly, or the server emitted an incremental part missing those fields.","commonSituations":"Custom Relay network handlers that mishandle @defer/@stream multipart responses; servers (or proxies) with non-conformant incremental delivery implementations; upgrading Relay while using an old server that predates the incremental-delivery spec fields; manually replaying/mocking incremental responses in tests without label/path.","solutions":["Log the raw incremental response before normalization and confirm the server includes `label` and `path` in every incremental part.","If writing a custom network layer, ensure each incremental part is passed through verbatim (including extensions/path) instead of being reconstructed.","Fix or upgrade the server's incremental delivery implementation to the spec so each payload has label and path.","If mocking, include label/path in test fixtures: { data: ..., label: '<DeferLabel>', path: [...] }.","Check that no middleware strips `label`/`path` fields from response parts."],"exampleFix":"// before\nnormalizationEngine.processIncrementalResponse({ data: item.data });\n// after\nnormalizationEngine.processIncrementalResponse({\n  data: item.data,\n  label: item.label,\n  path: item.path,\n});","handlingStrategy":"validation","validationCode":"function isValidIncrementalResponse(res) {\n  return res != null && res.label != null && res.path != null && typeof res.data === 'object' && res.data !== null;\n}\nif (!isValidIncrementalResponse(response)) throw new Error('Invalid incremental response');","typeGuard":"function hasLabelAndPath(res) {\n  return typeof res === 'object' && res !== null &&\n    typeof res.label === 'string' && Array.isArray(res.path);\n}","tryCatchPattern":"try {\n  normalizationEngine.processIncrementalResponse(response);\n} catch (e) {\n  if (String(e.message).includes('`label` and `path`')) {\n    console.error('Malformed incremental payload from network layer:', response);\n  } else throw e;\n}","preventionTips":["Validate multipart incremental payloads in your network layer before handing them to Relay.","Keep the server's incremental delivery implementation spec-compliant (label + path on every part).","Include label/path in all mocked incremental responses.","Avoid middleware that rewrites or strips response fields."],"tags":["relay","graphql","defer","stream","incremental-delivery"],"backgroundTag":"malformed-incremental-payload","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}