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

  1. Split the definitions into separate graphql`` tags, one per fragment/operation
  2. Check the template literal for stray text or copied extra definitions and delete them
  3. 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

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


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