facebook/relay · error
readFragment should be called only from within a Relay Resol
Error message
readFragment should be called only from within a Relay Resolver function.
What it means
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.
Source
Thrown at packages/relay-runtime/store/ResolverFragments.js:108
readonly $fragmentSpreads: FragmentType,
...
}>,
>(
fragmentInput: GraphQLTaggedNode,
fragmentKey: TKey,
): ?TKey?.[number]['$data'];
declare function readFragment<TKey extends FragmentType, TData>(
fragmentInput: Fragment<TKey, TData>,
fragmentKey: TKey,
): TData;
function readFragment(
fragmentInput: GraphQLTaggedNode,
fragmentKey: FragmentType,
): unknown {
if (!contextStack.length) {
throw new Error(
'readFragment should be called only from within a Relay Resolver function.',
);
}
const context = contextStack[contextStack.length - 1];
const fragmentNode = getFragment(fragmentInput);
const fragmentSelector = getSelector(fragmentNode, fragmentKey);
invariant(
fragmentSelector != null,
`Expected a selector for the fragment of the resolver ${fragmentNode.name}, but got null.`,
);
invariant(
fragmentSelector.kind === 'SingularReaderSelector',
`Expected a singular reader selector for the fragment of the resolver ${fragmentNode.name}, but it was plural.`,
);
const {data, isMissingData, fieldErrors} = context.getDataForResolverFragment(
fragmentSelector,
fragmentKey,
);View on GitHub (pinned to 668b1b85e0)
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
Example fix
// before
function myComponentRead(fragment, data) {
return readFragment(fragment, data); // throws: no resolver context
}
// after
function myComponentRead(fragment, data) {
return useFragment(fragment, data); // in a React component
} Defensive patterns
Strategy: type-guard
Validate before calling
null
Type guard
const canReadFragment = () => true; // no public way to check context; ensure calls are only inside Resolver bodies
Try / catch
try {
return readFragment(fragment, key);
} catch (e) {
if (String(e.message).includes('only from within a Relay Resolver function')) {
throw new Error('Use useFragment/environment.lookup outside Resolvers');
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Relay: Resolver error at path '${fieldError.fieldPath}' in '
- BabelPluginRelay: Expected plugin context to include "types"
- BabelPluginRelay: Expected exactly one definition per graphq
- BabelPluginRelay: Expected a fragment, mutation, query, or s
- GraphQL operations and fragments must contain names
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/1c64053abede1733.
Report an issue: GitHub.