{"record":{"id":"a738dd38626aef35","repo":"facebook/relay","slug":"normalizationengine-expected-id-of-elements-of-fi","errorCode":null,"errorMessage":"NormalizationEngine: Expected id of elements of field `${storageKey}` to be strings.","messagePattern":"NormalizationEngine: Expected id of elements of field `(.+?)` to be strings\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/store/NormalizationEngine.js","lineNumber":538,"sourceCode":"\n    const typeName = field.concreteType ?? (data as $FlowFixMe).__typename;\n    if (typeof typeName !== 'string') {\n      throw err(\n        'NormalizationEngine: Expected @stream field `' +\n          field.name +\n          '` to have a __typename.',\n      );\n    }\n\n    const getDataID = this._options.getDataID;\n    const itemID =\n      (typeof getDataID === 'function'\n        ? getDataID(data as $FlowFixMe, typeName)\n        : null) ??\n      prevIDs?.[itemIndex] ??\n      generateClientID(parentID, storageKey, itemIndex);\n    if (typeof itemID !== 'string') {\n      throw err(\n        'NormalizationEngine: Expected id of elements of field `' +\n          storageKey +\n          '` to be strings.',\n      );\n    }\n\n    const selector = createNormalizationSelector(field, itemID, variables);\n\n    const nextParentRecord = RelayModernRecord.clone(parentRecord);\n    const nextIDs = [...prevIDs];\n    nextIDs[itemIndex] = itemID;\n    RelayModernRecord.setLinkedRecordIDs(nextParentRecord, storageKey, nextIDs);\n    this._parentRecords.set(parentID, {\n      fieldPayloads,\n      record: nextParentRecord,\n    });\n\n    const relayPayload = this._normalizeResponse(","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/store/NormalizationEngine.js#L520-L556","documentation":"Relay resolves the streamed item's ID in order: a custom getDataID(options), the ID recorded previously at that list index, or a generated client ID. All three paths failed to produce a string — typically because a custom getDataID returned a non-string (e.g. a number or undefined) for this item, so Relay cannot key the record in the store. Relay requires all record IDs to be strings.","triggerScenarios":"Configuring the store with getDataID that returns a non-string (numeric ids, undefined when a field is missing) for items of the streamed field `storageKey`, causing `typeof itemID !== 'string'`.","commonSituations":"Apps with numeric (Int) database ids that implemented getDataID without String() conversion, ids nested under a different key than getDataID expects, or items where the id field is absent on some union members.","solutions":["Make your custom getDataID always return a string, coercing numbers with String(id)","Ensure every streamed item actually contains the field your getDataID reads","Return null (not a non-string) from getDataID when the id can't be derived so Relay falls back to prevIDs/client IDs","Log getDataID inputs during normalization to find which items yield non-string ids"],"exampleFix":"// before\nconst getDataID = (data) => data.id;\n// after\nconst getDataID = (data) => (data.id != null ? String(data.id) : null);","handlingStrategy":"type-guard","validationCode":"const data = payload.data as { id?: unknown };\nif (typeof getDataID?.(data, typeName) !== 'string') {\n  console.warn('getDataID returned non-string for streamed item', data);\n}","typeGuard":"function hasStringId(d: unknown): d is { id: string } {\n  return typeof (d as any)?.id === 'string' && (d as any).id.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Coerce ids to string inside getDataID","Return null from getDataID when id is unavailable so Relay falls back","Cover union/interface list items in tests where id shape varies"],"tags":["relay","stream","data-id","normalization"],"backgroundTag":"relay-stream-normalization","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}