babel/babel · error · Error

Unexpected replacement overlap.

Error message

Unexpected replacement overlap.

What it means

Tagged-literal templates generate internal placeholder names (prefixed with BABEL_TPL$, e.g. $$BABEL_TPL$0) for the ${} interpolation slots, then merge them with user-named replacements. If a user-supplied replacement key collides with one of these generated names, substitution is ambiguous and rejected.

Source

Thrown at packages/babel-template/src/literal.ts:26

  formatter: Formatter<T>,
  tpl: string[],
  opts: TemplateOpts,
): (_: unknown[]) => (_: unknown) => T {
  const { metadata, names } = buildLiteralData(formatter, tpl, opts);

  return arg => {
    const defaultReplacements: TemplateReplacements = {};
    arg.forEach((replacement, i) => {
      defaultReplacements[names[i]] = replacement;
    });

    return (arg: unknown) => {
      const replacements = normalizeReplacements(arg);

      if (replacements) {
        Object.keys(replacements).forEach(key => {
          if (Object.hasOwn(defaultReplacements, key)) {
            throw new Error("Unexpected replacement overlap.");
          }
        });
      }

      return formatter.unwrap(
        populatePlaceholders(
          metadata,
          replacements
            ? Object.assign(replacements, defaultReplacements)
            : defaultReplacements,
        ),
      );
    };
  };
}

function buildLiteralData<T>(
  formatter: Formatter<T>,

View on GitHub (pinned to 06b6eae39d)

Solutions

  1. Rename replacement keys to avoid the BABEL_TPL$ prefix.
  2. Do not mix positional ${x} substitutions with object keys that resemble the generated names.
  3. If you need control over names, use the string form template("code", opts) with explicit %%foo%% placeholders.

Example fix

// before
tpl`x`({ '$$BABEL_TPL$0': node })
// after
tpl`x`({ myKey: node })
Defensive patterns

Strategy: validation

Validate before calling

function assertNoBabelPrefix(replacements) {
  for (const k of Object.keys(replacements || {})) {
    if (k.includes('BABEL_TPL$')) throw new Error(`replacement key ${k} collides with internal prefix`);
  }
}

Prevention

When it happens

Trigger: Calling a tagged-literal builder with a replacements object whose key matches a generated name, e.g. tpl`...`({ '$$BABEL_TPL$0': node }) or any key beginning with the BABEL_TPL$ prefix.

Common situations: Rare; occurs when user replacement keys happen to match the generated prefix, or when array-form and object-form replacements are mixed in a way that collides.

Related errors


AI-assisted analysis of babel/babel@06b6eae39d (2026-08-03). Data as JSON: /data/errors/6b34d0236b823261.json. Report an issue: GitHub.