{"record":{"id":"1c64053abede1733","repo":"facebook/relay","slug":"readfragment-should-be-called-only-from-within-a-r","errorCode":null,"errorMessage":"readFragment should be called only from within a Relay Resolver function.","messagePattern":"readFragment should be called only from within a Relay Resolver function\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/relay-runtime/store/ResolverFragments.js","lineNumber":108,"sourceCode":"    readonly $fragmentSpreads: FragmentType,\n    ...\n  }>,\n>(\n  fragmentInput: GraphQLTaggedNode,\n  fragmentKey: TKey,\n): ?TKey?.[number]['$data'];\n\ndeclare function readFragment<TKey extends FragmentType, TData>(\n  fragmentInput: Fragment<TKey, TData>,\n  fragmentKey: TKey,\n): TData;\n\nfunction readFragment(\n  fragmentInput: GraphQLTaggedNode,\n  fragmentKey: FragmentType,\n): unknown {\n  if (!contextStack.length) {\n    throw new Error(\n      'readFragment should be called only from within a Relay Resolver function.',\n    );\n  }\n  const context = contextStack[contextStack.length - 1];\n  const fragmentNode = getFragment(fragmentInput);\n  const fragmentSelector = getSelector(fragmentNode, fragmentKey);\n  invariant(\n    fragmentSelector != null,\n    `Expected a selector for the fragment of the resolver ${fragmentNode.name}, but got null.`,\n  );\n  invariant(\n    fragmentSelector.kind === 'SingularReaderSelector',\n    `Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`,\n  );\n  const {data, isMissingData, fieldErrors} = context.getDataForResolverFragment(\n    fragmentSelector,\n    fragmentKey,\n  );","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/relay-runtime/store/ResolverFragments.js#L90-L126","documentation":"readFragment is a context-dependent internal helper for Relay Resolvers: it only works while a Resolver function is executing, tracked by contextStack. Calling it outside a Resolver (empty stack) throws because there is no Resolver context to read the fragment against.","triggerScenarios":"Calling readFragment from application code, a plain function, a React component, or an async callback that ran after the Resolver's synchronous execution finished (contextStack already popped).","commonSituations":"Trying to reuse Resolver helpers like readFragment in normal components instead of useFragment; calling it inside .then()/setTimeout within a Resolver so execution escapes the synchronous context; exporting it as a general-purpose store reader.","solutions":["Call readFragment only inside a Relay Resolver function body (synchronously)","Use useFragment (React) or environment.lookup in components/services instead of readFragment","Avoid awaiting/scheduling inside Resolvers before calling readFragment — keep reads synchronous","If you need data outside a Resolver, pass the Resolver result out rather than calling readFragment later"],"exampleFix":"// before\nfunction myComponentRead(fragment, data) {\n  return readFragment(fragment, data); // throws: no resolver context\n}\n// after\nfunction myComponentRead(fragment, data) {\n  return useFragment(fragment, data); // in a React component\n}","handlingStrategy":"type-guard","validationCode":"null","typeGuard":"const canReadFragment = () => true; // no public way to check context; ensure calls are only inside Resolver bodies","tryCatchPattern":"try {\n  return readFragment(fragment, key);\n} catch (e) {\n  if (String(e.message).includes('only from within a Relay Resolver function')) {\n    throw new Error('Use useFragment/environment.lookup outside Resolvers');\n  }\n  throw e;\n}","preventionTips":["Call readFragment only synchronously inside Resolver function bodies","Never call it in async continuations (then/setTimeout) inside Resolvers","Use useFragment or environment.lookup in components/services","Don't export readFragment wrappers as public helpers"],"tags":["relay","resolver","misused-api","context"],"backgroundTag":"api-called-outside-context","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}