swc-project/swc · warning

Fallback bindings does not support legacy plugins, it'll be

Error message

Fallback bindings does not support legacy plugins, it'll be ignored.

What it means

Warning from @swc/core's JS wrapper: the native binding did not load, so transforms run on fallbackBindings (@swc/wasm), which cannot execute the legacy JS `plugin` option (the (program) => Program hook). The plugin is ignored and the warning prints once per Compiler instance, so output silently lacks the plugin's transformations.

Source

Thrown at packages/core/src/index.ts:329

                            src,
                            options?.jsc?.parser,
                            options.filename
                        )
                        : src;
                return this.transform(
                    copyProgramSourceContext(m, plugin(m)),
                    newOptions
                );
            }

            return bindings.transform(
                isModule ? stringifyProgram(src) : src,
                isModule,
                toBuffer(newOptions)
            );
        } else if (fallbackBindings) {
            if (plugin && !this.fallbackBindingsPluginWarningDisplayed) {
                console.warn(
                    `Fallback bindings does not support legacy plugins, it'll be ignored.`
                );
                this.fallbackBindingsPluginWarningDisplayed = true;
            }

            return fallbackBindings.transform(src, options);
        }

        throw new Error("Bindings not found.");
    }

    transformSync(src: string | Program, options?: Options): Output {
        const isModule = typeof src !== "string";
        options = options || {};

        if (options?.jsc?.parser) {
            options.jsc.parser.syntax =
                options.jsc.parser.syntax ?? "ecmascript";

View on GitHub (pinned to 5176682b65)

Solutions

  1. Repair the native binding installation (npm install --include=optional, correct platform package) so the plugin path runs.
  2. Detect the fallback and fail fast instead of silently skipping the plugin (throw your own error when a plugin is requested).
  3. Move the transformation into config-driven passes that @swc/wasm supports if you must stay on wasm.
  4. Assert on output in tests so a skipped plugin is caught before shipping.

Example fix

// before: plugin silently ignored on wasm fallback
const out = await compiler.transform(src, { plugin: myPlugin, ...opts });

// after: fail fast when the plugin cannot run
import * as os from 'os';
function assertNativeForPlugin(plugin: unknown) {
  if (!plugin) return;
  const { optionalDependencies } = require('@swc/core/package.json');
  const tri = `@swc/core-${os.platform()}-${os.arch()}`;
  const native = Object.keys(optionalDependencies).some(
    (d) => d.startsWith(tri) && (() => { try { require.resolve(d); return true; } catch { return false; } })()
  );
  if (!native) throw new Error('SWC plugin requires native bindings; @swc/wasm fallback ignores plugins');
}
assertNativeForPlugin(myPlugin);
const out = await compiler.transform(src, { plugin: myPlugin, ...opts });
Defensive patterns

Strategy: validation

Validate before calling

// Detect the wasm fallback before passing a plugin the wrapper will ignore.
import * as os from 'os';
function nativeBindingResolves(): boolean {
  try {
    const { optionalDependencies } = require('@swc/core/package.json');
    const tri = `@swc/core-${os.platform()}-${os.arch()}`;
    return Object.keys(optionalDependencies ?? {}).some(
      (d) => d.startsWith(tri) && (() => { try { require.resolve(d); return true; } catch { return false; } })()
    );
  } catch {
    return false;
  }
}
function assertPluginsRunnable(plugin: unknown): void {
  if (plugin && !nativeBindingResolves()) {
    throw new Error('@swc/wasm fallback cannot run legacy plugins; fix the native binding or drop the plugin option');
  }
}

Type guard

function hasNativeBindings(): boolean {
  const os = require('os');
  const { optionalDependencies } = require('@swc/core/package.json');
  const tri = `@swc/core-${os.platform()}-${os.arch()}`;
  return Object.keys(optionalDependencies ?? {}).some(
    (d) => d.startsWith(tri) && (() => { try { require.resolve(d); return true; } catch { return false; } })()
  );
}

Prevention

When it happens

Trigger: await compiler.transform(src, { plugin: (m) => { ...; return m; }, ... }) while the native @swc/core binary is unavailable and the @swc/wasm fallback is in use.

Common situations: Native install failed (missing optional dep, unsupported arch) but code still passes a plugin; browser/electron setups relying on wasm; teams not noticing output differences because only a console.warn fires.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/7112d82508870658. Report an issue: GitHub.