babel/babel · error · Error

`experimental_preserveFormat` is not compatible with the `js

Error message

`experimental_preserveFormat` is not compatible with the `jsescOption` option

What it means

`jsescOption` customizes string escaping, which would alter the exact bytes preserveFormat is meant to retain. At index.ts:45-49, if `experimental_preserveFormat` is on and `jsescOption` is set, the generator throws.

Source

Thrown at packages/babel-generator/src/index.ts:46

      );
    }
    if (!opts.retainLines) {
      throw new Error(
        "`experimental_preserveFormat` requires `retainLines` to be set to `true`",
      );
    }
    if (opts.compact && opts.compact !== "auto") {
      throw new Error(
        "`experimental_preserveFormat` is not compatible with the `compact` option",
      );
    }
    if (opts.minified) {
      throw new Error(
        "`experimental_preserveFormat` is not compatible with the `minified` option",
      );
    }
    if (opts.jsescOption) {
      throw new Error(
        "`experimental_preserveFormat` is not compatible with the `jsescOption` option",
      );
    }
    if (!Array.isArray((ast as any).tokens)) {
      throw new Error(
        "`experimental_preserveFormat` requires the AST to have attached the token of the input code. Make sure to enable the `tokens: true` parser option.",
      );
    }
  }

  const format: Format = {
    auxiliaryCommentBefore: opts.auxiliaryCommentBefore,
    auxiliaryCommentAfter: opts.auxiliaryCommentAfter,
    // @ts-expect-error define it later
    shouldPrintComment: opts.shouldPrintComment,
    preserveFormat: opts.experimental_preserveFormat,
    retainLines: opts.retainLines,
    retainFunctionParens: opts.retainFunctionParens,

View on GitHub (pinned to 06b6eae39d)

Solutions

  1. Remove the `jsescOption` from generator options when using experimental_preserveFormat.

Example fix

// before
generate(ast, { experimental_preserveFormat: true, jsescOption: { quotes: 'single' }, retainLines: true }, code);

// after
generate(ast, { experimental_preserveFormat: true, retainLines: true }, code);
Defensive patterns

Strategy: validation

Validate before calling

function assertPreserveFormatCompatible(opts) {
  if (opts.experimental_preserveFormat && opts.jsescOption) {
    throw new Error('experimental_preserveFormat is incompatible with jsescOption');
  }
}

Type guard

const preserveFormatJsescOk = (opts) =>
  !opts.experimental_preserveFormat || !opts.jsescOption;

Try / catch

try {
  generate(ast, opts, code);
} catch (err) {
  if (/not compatible with the .jsescOption. option/.test(err.message)) {
    const { jsescOption, ...rest } = opts;
    generate(ast, rest, code);
  } else throw err;
}

Prevention

When it happens

Trigger: Passing both `experimental_preserveFormat: true` and a `jsescOption` object.

Common situations: Carrying over quote/escape preferences from an existing generator config into a preserveFormat pipeline.

Related errors


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