facebook/relay · error
requestSubscription: Must use Subscription operation
Error message
requestSubscription: Must use Subscription operation
What it means
requestSubscription requires the tagged node passed in config.subscription to be a subscription operation. It checks subscription.params.operationKind and throws for queries or mutations, since only subscriptions support the long-lived executor/streaming semantics.
Source
Thrown at packages/relay-runtime/subscription/requestSubscription.js:62
export type GraphQLSubscriptionConfig<TVariables, TData, TRawResponse> =
Readonly<{
configs?: Array<DeclarativeMutationConfig>,
cacheConfig?: CacheConfig,
subscription: GraphQLSubscription<TVariables, TData, TRawResponse>,
variables: NoInfer<TVariables>,
onCompleted?: ?() => void,
onError?: ?(error: Error) => void,
onNext?: ?(response: ?TData) => void,
updater?: ?SelectorStoreUpdater<TData>,
}>;
function requestSubscription<TVariables extends Variables, TData, TRawResponse>(
environment: IEnvironment,
config: GraphQLSubscriptionConfig<TVariables, TData, TRawResponse>,
): Disposable {
const subscription = getRequest(config.subscription);
if (subscription.params.operationKind !== 'subscription') {
throw new Error('requestSubscription: Must use Subscription operation');
}
const {configs, onCompleted, onError, onNext, variables, cacheConfig} =
config;
const operation = createOperationDescriptor(
subscription,
variables,
cacheConfig,
);
warning(
!(config.updater && configs),
'requestSubscription: Expected only one of `updater` and `configs` to be provided',
);
const {updater} = configs
? RelayDeclarativeMutationConfig.convert<$FlowFixMe>(
configs,
subscription,View on GitHub (pinned to 668b1b85e0)
Solutions
- Pass an operation declared with graphql`subscription ... {...}`
- Use commitMutation for mutations or fetchQuery for queries instead
- Verify operationKind at the call site if the tag comes from a shared constant
- Enable Relay's typed graphql (relay-compiler) so mismatched kinds are caught at build time
Example fix
// before
requestSubscription(env, {subscription: graphql`query R { ... }`, variables});
// after
requestSubscription(env, {subscription: graphql`subscription S { ... }`, variables}); Defensive patterns
Strategy: validation
Validate before calling
const sub = getRequest(config.subscription);
if (sub.params.operationKind !== 'subscription') {
throw new TypeError('requestSubscription requires a subscription operation, got ' + sub.params.operationKind);
} Type guard
const isSubscriptionOp = (tag) => getRequest(tag).params.operationKind === 'subscription';
Try / catch
try {
requestSubscription(env, config);
} catch (e) {
if (e.message === 'requestSubscription: Must use Subscription operation') {
throw new Error('config.subscription must be a graphql`subscription ...` operation');
}
throw e;
} Prevention
- Use relay-compiler typed graphql so kinds are enforced at compile time
- Name subscription tags consistently (xxxSubscription)
- Route mutations to commitMutation and queries to fetchQuery
- Review shared fragment exports before wiring subscription configs
When it happens
Trigger: Calling requestSubscription(env, {subscription: graphql`query ...` or `mutation ...`}) — the operation kind check fails.
Common situations: Reusing a query/mutation tag in a subscription config after refactoring; copy-pasting requestSubscription boilerplate without changing the operation; TypeScript not catching it because the tag is loosely typed.
Related errors
- fetchQuery: Expected query operation
- BabelPluginRelay: Expected exactly one definition per graphq
- BabelPluginRelay: Expected a fragment, mutation, query, or s
- GraphQL operations and fragments must contain names
- BabelPluginRelay: Substitutions are not allowed in graphql f
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/abcef50a019efc21.
Report an issue: GitHub.