{"record":{"id":"fafc4073606d38c7","repo":"facebook/relay","slug":"normalizationengine-expected-stream-to-be-used-o","errorCode":null,"errorMessage":"NormalizationEngine: Expected @stream to be used on a plural field.","messagePattern":"NormalizationEngine: Expected @stream to be used on a plural field\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/store/NormalizationEngine.js","lineNumber":384,"sourceCode":"  // ---------------------------------------------------------------------------\n  // Private: @stream handling\n  // ---------------------------------------------------------------------------\n\n  _processStream(\n    response: GraphQLResponseWithData,\n    path: ReadonlyArray<unknown>,\n    placeholder: StreamPlaceholder,\n  ): NormalizationResult {\n    const {node, parentID, variables} = placeholder;\n\n    // Find the LinkedField where @stream was applied\n    const field = node.selections[0];\n    if (\n      field == null ||\n      field.kind !== 'LinkedField' ||\n      field.plural !== true\n    ) {\n      throw err(\n        'NormalizationEngine: Expected @stream to be used on a plural field.',\n      );\n    }\n\n    const {\n      fieldPayloads,\n      itemID,\n      itemIndex,\n      prevIDs,\n      relayPayload,\n      storageKey,\n    } = this._normalizeStreamItem(\n      response,\n      parentID,\n      field,\n      variables,\n      path,\n      placeholder.path,","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/store/NormalizationEngine.js#L366-L402","documentation":"When normalizing an @stream payload, Relay extracts the first selection from the streamed field node and requires it to be a LinkedField with `plural: true`, because @stream only makes sense on list-typed fields where items arrive incrementally. If the field node is missing, not a LinkedField, or is singular, Relay throws since it cannot stream a non-plural field.","triggerScenarios":"A @stream directive is placed on a singular (non-list) field in the query, or the normalized AST node for the streamed field is not a plural LinkedField — e.g. the selection node passed to `_processStream` (via processIncrementalResponse/_registerPlaceholders) corresponds to a scalar or single object field.","commonSituations":"Developers adding @stream to a field whose GraphQL type is not a list; schema changes turning a formerly plural field singular while cached queries still use @stream; client/server directive mismatch where the server streams a field the client typed as singular.","solutions":["Find the field with @stream in the query and verify its GraphQL type is a list ([Type]); remove @stream if it is singular.","Re-fetch/refresh the query so client-side normalized AST matches the current schema if the field's type changed.","Ensure the server only streams fields the client annotated with @stream and that both sides agree the field is plural.","Update the persisted query / compiled artifacts if the query was compiled before a schema change."],"exampleFix":"// before\nquery { friends @stream(initialCount: 1) { name } } // if friends is a single object\n// after\nquery { friend @stream(initialCount: 1) { name } } // only if friend: [Friend] is plural; otherwise drop @stream\n","handlingStrategy":"validation","validationCode":"// Validate at build/query time: only apply @stream to list fields\nfunction assertStreamOnPlural(field) {\n  if (field.directives.some(d => d.name === 'stream') && !field.isList) {\n    throw new Error('@stream requires a plural (list) field: ' + field.name);\n  }\n}","typeGuard":"function isPluralLinkedField(node) {\n  return node != null && node.kind === 'LinkedField' && node.plural === true;\n}","tryCatchPattern":"try {\n  normalizationEngine.processIncrementalResponse(response);\n} catch (e) {\n  if (String(e.message).includes('@stream to be used on a plural field')) {\n    console.error('Query misuses @stream on a non-list field — fix the query');\n  } else throw e;\n}","preventionTips":["Only annotate list-typed GraphQL fields with @stream.","Regenerate compiled queries after schema type changes.","Keep client @stream usage and server streaming behavior aligned.","Lint custom Relay AST transforms to verify plural flags on streamed fields."],"tags":["relay","graphql","stream","query-validation"],"backgroundTag":"stream-on-non-plural-field","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}