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

  1. Call readFragment only inside a Relay Resolver function body (synchronously)
  2. Use useFragment (React) or environment.lookup in components/services instead of readFragment
  3. Avoid awaiting/scheduling inside Resolvers before calling readFragment — keep reads synchronous
  4. 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

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


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/1c64053abede1733. Report an issue: GitHub.