facebook/relay · error

BabelPluginRelay: Substitutions are not allowed in graphql f

Error message

BabelPluginRelay: Substitutions are not allowed in graphql fragments. Included fragments should be referenced as `...MyModule_propName`.

What it means

Relay's graphql`` tags must be pure string literals: the template's quasis must be exactly one chunk with zero ${} substitutions. Dynamic interpolation would make the GraphQL document unknowable at build time, so the plugin throws. Included fragments should be referenced statically with `...MyModule_propName` spread syntax instead.

Source

Thrown at packages/babel-plugin-relay/getValidGraphQLTag.js:33

const GraphQL = require('graphql');

/**
 * Given a babel AST path to a tagged template literal, return an AST if it is
 * a graphql literal being used in a valid way.
 * If it is some other type of template literal then return nothing.
 */
function getValidGraphQLTag(path: any): ?DocumentNode {
  const tag = path.get('tag');

  if (!tag.isIdentifier({name: 'graphql'})) {
    return null;
  }

  const quasis = path.node.quasi.quasis;

  if (quasis.length !== 1) {
    throw new Error(
      'BabelPluginRelay: Substitutions are not allowed in graphql fragments. ' +
        'Included fragments should be referenced as `...MyModule_propName`.',
    );
  }

  const text = quasis[0].value.raw;

  const ast = GraphQL.parse(text, {experimentalFragmentVariables: true});

  if (ast.definitions.length === 0) {
    throw new Error('BabelPluginRelay: Unexpected empty graphql tag.');
  }

  return ast;
}

module.exports = getValidGraphQLTag;

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Remove all ${...} interpolations and write the GraphQL text statically
  2. Replace dynamically injected sub-selections with fragment spreads: `...SomeModule_propName`
  3. If field reuse is needed, define a named fragment once and spread it into the consuming fragment

Example fix

// before
const fields = 'id name';
const frag = graphql`fragment F on User { ${fields} }`;

// after
const frag = graphql`
  fragment F on User {
    id
    name
  }
`;
Defensive patterns

Strategy: validation

Validate before calling

function assertNoSubstitutions(taggedTemplateNode) {
  if (taggedTemplateNode.quasi.expressions.length > 0 || taggedTemplateNode.quasi.quasis.length !== 1) {
    throw new Error('graphql`` tags must not contain ${} substitutions');
  }
}

Type guard

const isStaticTemplate = (node) =>
  node && node.quasi && node.quasi.expressions.length === 0 && node.quasi.quasis.length === 1;

Prevention

When it happens

Trigger: A graphql`` template containing an interpolation, e.g. graphql`fragment F on User ${someField} {...}` or graphql`query { ${variable} }`, making template.quasi.quasis.length > 1.

Common situations: Trying to build queries dynamically from variables; generating field lists at runtime; templating shared field sets via JS variables instead of fragment spreads.

Related errors


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