facebook/relay · error
BabelPluginRelay: Expected exactly one definition per graphq
Error message
BabelPluginRelay: Expected exactly one definition per graphql tag.
What it means
A graphql`` tagged template in Relay must contain exactly one GraphQL definition (one fragment, query, mutation, or subscription). The plugin parses the template's text into a DocumentNode and throws when ast.definitions.length !== 1. Multiple definitions in a single graphql tag are not supported because each tag compiles to exactly one artifact.
Source
Thrown at packages/babel-plugin-relay/compileGraphQLTag.js:54
* cross-platform compatibility.
*/
function posixifyPath(path: string): string {
// $FlowFixMe[cannot-resolve-name]
return process.platform === 'win32' ? path.replace(/\\/g, '/') : path;
}
/**
* Given a graphql`` tagged template literal, replace it with the appropriate
* runtime artifact.
*/
function compileGraphQLTag(
t: $FlowFixMe,
path: Object,
state: BabelState,
ast: DocumentNode,
): void {
if (ast.definitions.length !== 1) {
throw new Error(
'BabelPluginRelay: Expected exactly one definition per graphql tag.',
);
}
const definition = ast.definitions[0];
if (
definition.kind !== 'FragmentDefinition' &&
definition.kind !== 'OperationDefinition'
) {
throw new Error(
'BabelPluginRelay: Expected a fragment, mutation, query, or ' +
'subscription, got `' +
definition.kind +
'`.',
);
}
const eagerEsModules = state.opts?.eagerEsModules ?? true;
const isHasteMode = state.opts?.jsModuleFormat === 'haste';View on GitHub (pinned to 668b1b85e0)
Solutions
- Split the definitions into separate graphql`` tags, one per fragment/operation
- Check the template literal for stray text or copied extra definitions and delete them
- If composing, reference other fragments via spread syntax `...OtherFragment_name` inside one fragment instead of declaring them together
Example fix
// before
const query = graphql`
fragment A on User { id }
fragment B on User { name }
`;
// after
const fragmentA = graphql`fragment A on User { id }`;
const fragmentB = graphql`fragment B on User { name }`; Defensive patterns
Strategy: validation
Validate before calling
function assertSingleDefinition(text) {
const ast = require('graphql').parse(text);
if (ast.definitions.length !== 1) {
throw new Error(`graphql tag must contain exactly one definition, got ${ast.definitions.length}`);
}
} Type guard
const hasSingleDefinition = (ast) => ast && Array.isArray(ast.definitions) && ast.definitions.length === 1;
Prevention
- Keep one operation/fragment per graphql`` tag
- Use a lint rule (e.g. eslint-plugin-graphql / relay compiler in CI) to catch multi-definition tags
- Reference shared fields via fragment spreads rather than combining definitions
When it happens
Trigger: A graphql`` template literal whose text parses to two or more definitions, e.g. graphql`fragment F on T {...} fragment G on U {...}`, or a tag that accidentally includes multiple statements separated by whitespace/comments.
Common situations: Copy-pasting several fragments into one tag; concatenating queries when refactoring; tooling that merges GraphQL documents into a single template literal.
Related errors
- BabelPluginRelay: Expected a fragment, mutation, query, or s
- GraphQL operations and fragments must contain names
- BabelPluginRelay: Substitutions are not allowed in graphql f
- BabelPluginRelay: Unexpected empty graphql tag.
- BabelPluginRelay: Expected plugin context to include "types"
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/66a7871259ec08c4.
Report an issue: GitHub.