facebook/relay · error

Unexpected null response from fetchQuery

Error message

Unexpected null response from fetchQuery

What it means

serverFetchQuery is an RSC (React Server Components) wrapper around Relay's fetchQuery. It awaits the observable's promise and throws if Relay resolves with null/undefined, which should never happen for a well-formed query — a null result indicates the environment or network layer returned an empty payload instead of data or an error.

Source

Thrown at packages/react-relay/relay-hooks/rsc/serverFetchQuery.js:26

 * @format
 * @oncall relay
 */

'use strict';

import type {IEnvironment, Query, Variables} from 'relay-runtime';

const {fetchQuery} = require('relay-runtime');

async function serverFetchQuery<TVariables extends Variables, TData>(
  environment: IEnvironment,
  query: Query<TVariables, TData>,
  variables: TVariables,
): Promise<TData> {
  const observable = fetchQuery(environment, query, variables);
  const result = await observable.toPromise();
  if (result == null) {
    throw new Error('Unexpected null response from fetchQuery');
  }
  return result;
}

module.exports = serverFetchQuery;

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Inspect the network layer's fetch function and make sure it always resolves with a valid GraphQLResponse containing a 'data' or 'errors' field
  2. Check that the fetch response body is being parsed (e.g. await response.json()) and that the server actually returns a body for this query
  3. Verify the environment passed to serverFetchQuery is a fully configured RelayModernEnvironment, not an empty/placeholder environment
  4. If the error is expected (e.g. legitimately nullable data), handle the null in the network layer or wrap the call and surface a domain-specific error

Example fix

// before
const network = Network.create(() => fetch(url));
// after
const network = Network.create(async (params, vars) => {
  const res = await fetch(url, {method: 'POST', body: JSON.stringify({query: params.text, variables: vars})});
  if (!res.ok) throw new Error(`GraphQL request failed: ${res.status}`);
  return res.json(); // must resolve with {data} or {errors}
});
Defensive patterns

Strategy: try-catch

Validate before calling

const network = environment.getNetwork(); // verify fetch always resolves {data} or {errors}
// sanity check before use:
function isValidResponse(r) { return r != null && ('data' in r || 'errors' in r); }

Type guard

function isGraphQLResponse(r: unknown): r is {data: unknown} { return typeof r === 'object' && r !== null && 'data' in r; }

Try / catch

try {
  const data = await serverFetchQuery(environment, query, variables);
} catch (e) {
  if (e.message.includes('Unexpected null response')) {
    // network layer returned null: log request id/params and surface a server error
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling serverFetchQuery(environment, query, variables) in a server environment when the network layer's fetch resolves with null/undefined (e.g. missing response body, custom network layer returning undefined, or environment misconfiguration) instead of a valid GraphQLResponse.

Common situations: RSC server-side rendering with a misconfigured network layer; a fetch function that returns response.json() of an empty body (204/empty 200); a network layer that swallows errors and resolves undefined; SSR data prefetch where the environment has no handler for the query.


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