facebook/relay · error
commitMutation: Expected mutation operation
Error message
commitMutation: Expected mutation operation
What it means
commitMutation in relay-runtime checks that the request object built from config.mutation has operationKind 'mutation'. Supplying a compiled query or subscription throws this error before any network work begins.
Source
Thrown at packages/relay-runtime/mutations/commitMutation.js:96
* Higher-level helper function to execute a mutation against a specific
* environment.
*/
function commitMutation<
TVariables extends Variables,
TData,
TRawResponse = {...},
>(
environment: IEnvironment,
config: CommitMutationConfig<TVariables, TData, TRawResponse>,
): Disposable {
invariant(
isRelayModernEnvironment(environment),
'commitMutation: expected `environment` to be an instance of ' +
'`RelayModernEnvironment`.',
);
const mutation = getRequest(config.mutation);
if (mutation.params.operationKind !== 'mutation') {
throw new Error('commitMutation: Expected mutation operation');
}
if (mutation.kind !== 'Request') {
throw new Error('commitMutation: Expected mutation to be of type request');
}
let {optimisticResponse, optimisticUpdater, updater} = config;
const {configs, cacheConfig, onError, onUnsubscribe, variables, uploadables} =
config;
const operation = createOperationDescriptor(
mutation,
variables,
cacheConfig,
generateUniqueClientID(),
);
// TODO: remove this check after we fix flow.
if (typeof optimisticResponse === 'function') {
/* $FlowFixMe[incompatible-use] error exposed when improving flow typing of
* commitMutation */
optimisticResponse = optimisticResponse();View on GitHub (pinned to 668b1b85e0)
Solutions
- Verify the .graphql file passed to relay-compiler uses `mutation` as the operation keyword and recompile
- Confirm the import in config.mutation matches the generated artifact of the mutation (check params.operationKind in the artifact)
- Use requestSubscription or fetchQuery if the operation is genuinely not a mutation
Example fix
// before
import CandidateQuery from './__generated__/CandidateQuery.graphql';
commitMutation(env, {mutation: CandidateQuery, ...});
// after
import CandidateMutation from './__generated__/CandidateMutation.graphql';
commitMutation(env, {mutation: CandidateMutation, ...}); Defensive patterns
Strategy: validation
Validate before calling
import {getRequest} from 'relay-runtime';
const mutation = getRequest(config.mutation);
if (mutation.params.operationKind !== 'mutation') {
throw new Error(`${mutation.params.name} is a ${mutation.params.operationKind}, not a mutation`);
} Type guard
function isCommitableMutation(m: {params: {operationKind: string}}): m is {params: {operationKind: 'mutation'}} {
return m.params.operationKind === 'mutation';
} Try / catch
try {
const id = commitMutation(environment, config);
} catch (e) {
if (e.message.includes('Expected mutation operation')) {
// wrong operation kind — redirect to requestSubscription/fetchQuery as appropriate
}
} Prevention
- Import generated artifacts from the mutation's own __generated__ file
- Verify params.operationKind in code review when wiring mutations
- Use TypeScript $Parameters so mismatched artifacts are compile errors
- Keep operation names unique to avoid auto-import confusion
When it happens
Trigger: commitMutation(environment, {mutation: <generated query or subscription artifact>}) — i.e. the GraphQL document's operation keyword is `query` or `subscription` rather than `mutation`.
Common situations: Wrong generated module imported (auto-import picked the query file with a similar name); the .graphql operation keyword was changed or mistyped; renaming operations so the mutation import now points at a query artifact.
Related errors
- commitMutation: Expected mutation operation
- commitMutation: Expected mutation to be of type request
- unexpected value for @defer if argument: {other:?}
- unexpected value for @stream if argument: {other:?}
- Expected client edge backing field to be transformed into ex
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/3adb95f32f2eee9a.
Report an issue: GitHub.