{"record":{"id":"88e88f4bb10f9a28","repo":"facebook/relay","slug":"babelpluginrelay-substitutions-are-not-allowed-in","errorCode":null,"errorMessage":"BabelPluginRelay: Substitutions are not allowed in graphql fragments. Included fragments should be referenced as `...MyModule_propName`.","messagePattern":"BabelPluginRelay: Substitutions are not allowed in graphql fragments\\. Included fragments should be referenced as `\\.\\.\\.MyModule_propName`\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/babel-plugin-relay/getValidGraphQLTag.js","lineNumber":33,"sourceCode":"\nconst GraphQL = require('graphql');\n\n/**\n * Given a babel AST path to a tagged template literal, return an AST if it is\n * a graphql literal being used in a valid way.\n * If it is some other type of template literal then return nothing.\n */\nfunction getValidGraphQLTag(path: any): ?DocumentNode {\n  const tag = path.get('tag');\n\n  if (!tag.isIdentifier({name: 'graphql'})) {\n    return null;\n  }\n\n  const quasis = path.node.quasi.quasis;\n\n  if (quasis.length !== 1) {\n    throw new Error(\n      'BabelPluginRelay: Substitutions are not allowed in graphql fragments. ' +\n        'Included fragments should be referenced as `...MyModule_propName`.',\n    );\n  }\n\n  const text = quasis[0].value.raw;\n\n  const ast = GraphQL.parse(text, {experimentalFragmentVariables: true});\n\n  if (ast.definitions.length === 0) {\n    throw new Error('BabelPluginRelay: Unexpected empty graphql tag.');\n  }\n\n  return ast;\n}\n\nmodule.exports = getValidGraphQLTag;\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/packages/babel-plugin-relay/getValidGraphQLTag.js#L15-L51","documentation":"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.","triggerScenarios":"A graphql`` template containing an interpolation, e.g. graphql`fragment F on User ${someField} {...}` or graphql`query { ${variable} }`, making template.quasi.quasis.length > 1.","commonSituations":"Trying to build queries dynamically from variables; generating field lists at runtime; templating shared field sets via JS variables instead of fragment spreads.","solutions":["Remove all ${...} interpolations and write the GraphQL text statically","Replace dynamically injected sub-selections with fragment spreads: `...SomeModule_propName`","If field reuse is needed, define a named fragment once and spread it into the consuming fragment"],"exampleFix":"// before\nconst fields = 'id name';\nconst frag = graphql`fragment F on User { ${fields} }`;\n\n// after\nconst frag = graphql`\n  fragment F on User {\n    id\n    name\n  }\n`;","handlingStrategy":"validation","validationCode":"function assertNoSubstitutions(taggedTemplateNode) {\n  if (taggedTemplateNode.quasi.expressions.length > 0 || taggedTemplateNode.quasi.quasis.length !== 1) {\n    throw new Error('graphql`` tags must not contain ${} substitutions');\n  }\n}","typeGuard":"const isStaticTemplate = (node) =>\n  node && node.quasi && node.quasi.expressions.length === 0 && node.quasi.quasis.length === 1;","tryCatchPattern":null,"preventionTips":["Never interpolate JavaScript variables into graphql`` tags","Reuse fields with named fragment spreads (...SomeModule_propName) instead of templating","Enable eslint-plugin-relay rules to flag dynamic graphql templates"],"tags":["babel","build-time","graphql","relay"],"backgroundTag":"invalid-graphql-tag","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}