facebook/relay · error

GraphQL operations and fragments must contain names

Error message

GraphQL operations and fragments must contain names

What it means

Relay requires every operation and fragment to have an explicit name so it can generate named artifacts and derive the module require path. This branch (getRequiredModulePath-style logic) computes a filename like `${definitionName}.graphql` for haste-mode or artifact resolution and throws if the definition's name is absent. Anonymous operations/fragments cannot be compiled.

Source

Thrown at packages/babel-plugin-relay/compileGraphQLTag.js:119

  graphqlDefinition: OperationDefinitionNode | FragmentDefinitionNode,
  options: {
    // If an output directory is specified when running relay-compiler this should point to that directory
    artifactDirectory: ?string,
    // Generate eager es modules instead of lazy require
    eagerEsModules: boolean,
    // The command to run to compile Relay files, used for error messages.
    buildCommand: string,
    // Generate extra validation, defaults to true.
    isDevelopment: boolean,
    // Wrap the validation code in a conditional checking this variable.
    isDevVariable: ?string,
    // Use haste style global requires, defaults to false.
    isHasteMode: boolean,
  },
): Object {
  const definitionName = graphqlDefinition.name && graphqlDefinition.name.value;
  if (!definitionName) {
    throw new Error('GraphQL operations and fragments must contain names');
  }
  const requiredFile = definitionName + '.graphql';
  const requiredPath = posixifyPath(
    options.isHasteMode
      ? requiredFile
      : options.artifactDirectory
        ? getRelativeImportPath(state, options.artifactDirectory, requiredFile)
        : GENERATED + requiredFile,
  );

  const hash = crypto
    .createHash('md5')
    .update(print(graphqlDefinition), 'utf8')
    .digest('hex');

  let topScope = path.scope;
  while (topScope.parent) {
    topScope = topScope.parent;

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Add a unique name: query ViewerQuery { ... } instead of query { ... }
  2. Ensure fragments are declared as fragment Name on Type { ... } with the name present
  3. Run Relay compiler separately to surface naming errors with better messages before Babel runs

Example fix

// before
const data = graphql`query { viewer { id } }`;

// after
const data = graphql`query ViewerQuery { viewer { id } }`;
Defensive patterns

Strategy: validation

Validate before calling

function assertNamed(text) {
  const { parse } = require('graphql');
  const def = parse(text).definitions[0];
  if (!def.name || !def.name.value) {
    throw new Error('Relay requires every operation/fragment to have a name');
  }
}

Type guard

const isNamed = (def) =>
  !!def && !!def.name && typeof def.name.value === 'string' && def.name.value.length > 0;

Prevention

When it happens

Trigger: A graphql`` tag containing an anonymous operation (e.g. graphql`query { viewer { id } }`) or a fragment missing its name token, so graphqlDefinition.name is null or name.value is empty.

Common situations: Writing shorthand anonymous queries copied from a playground; accidentally deleting the fragment name during refactoring; codegen output that emits unnamed operations.

Related errors


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