facebook/relay · error

fetchQuery: Expected query operation

Error message

fetchQuery: Expected query operation

What it means

fetchQuery_DEPRECATED only supports GraphQL queries: it executes an operation and resolves with its data. The throw guards against passing a mutation/subscription fragment, whose execution semantics differ, so Relay rejects it up front.

Source

Thrown at packages/relay-runtime/query/fetchQuery_DEPRECATED.js:37

  createOperationDescriptor,
} = require('../store/RelayModernOperationDescriptor');
const {getRequest} = require('./GraphQLTag');

/**
 * A helper function to fetch the results of a query. Note that results for
 * fragment spreads are masked: fields must be explicitly listed in the query in
 * order to be accessible in the result object.
 */

function fetchQuery_DEPRECATED<T extends OperationType>(
  environment: IEnvironment,
  taggedNode: GraphQLTaggedNode,
  variables: T['variables'],
  cacheConfig?: ?CacheConfig,
): Promise<T['response']> {
  const query = getRequest(taggedNode);
  if (query.params.operationKind !== 'query') {
    throw new Error('fetchQuery: Expected query operation');
  }
  const operation = createOperationDescriptor(query, variables, cacheConfig);
  return environment
    .execute({operation})
    .map(() => environment.lookup(operation.fragment).data)
    .toPromise();
}

module.exports = fetchQuery_DEPRECATED;

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Pass a query operation (use graphql`query ... {...}`) to fetchQuery
  2. Use commitMutation (relay-experimental/commitMutation or environment) for mutations instead of fetchQuery
  3. Use requestSubscription for subscriptions
  4. Migrate off fetchQuery_DEPRECATED to fetchQuery, which produces a clearer pathway

Example fix

// before
fetchQuery_DEPRECATED(env, graphql`mutation M { ... }`, vars);
// after
commitMutation(env, {mutation: graphql`mutation M { ... }`, variables: vars});
Defensive patterns

Strategy: validation

Validate before calling

const req = getRequest(taggedNode);
if (req.params.operationKind !== 'query') {
  throw new TypeError('fetchQuery requires a query operation, got ' + req.params.operationKind);
}

Type guard

const isQueryOp = (tag) => getRequest(tag).params.operationKind === 'query';

Try / catch

try {
  return await fetchQuery_DEPRECATED(env, tag, vars);
} catch (e) {
  if (e.message === 'fetchQuery: Expected query operation') {
    throw new Error('Pass queries to fetchQuery; use commitMutation/requestSubscription for other kinds');
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing a graphql-tagged node whose params.operationKind is 'mutation' or 'subscription' to the deprecated fetchQuery(environment, taggedNode, variables) helper.

Common situations: Using a shared fragment/mutation constant by mistake in a preloading helper; refactoring code where the tag changed kind; forgetting that commitMutation/requestSubscription are the right entry points for non-query operations.

Related errors


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