swc-project/swc · critical

Should able to be deserialized into string

Error message

Should able to be deserialized into string

What it means

Host-side handler for a wasm plugin's `emit` call in swc_plugin_runner. It copies bytes from the plugin's linear memory and decodes them as versioned CBOR into `PluginEmitOutput`; when decoding fails, the `.expect(...)` panics. The bytes were encoded by the guest using its own swc_core serialization code, so this panic almost always means the plugin was built against a swc_core whose wire schema differs from the host runner's, or the guest wrote garbage/incorrect length.

Source

Thrown at crates/swc_plugin_runner/src/imported_fn/handler.rs:45

            );
            builder.emit();
        })
    }
}

pub fn emit_output(
    caller: &mut dyn runtime::Caller<'_>,
    _env: &BaseHostEnvironment,
    output_ptr: i32,
    output_len: i32,
) {
    let mut output_bytes = Vec::new();
    copy_bytes_into_host(caller, output_ptr, output_len, &mut output_bytes);
    let serialized = PluginSerializedBytes::from_bytes(output_bytes);
    let output = PluginSerializedBytes::deserialize::<swc_common::plugin::emit::PluginEmitOutput>(
        &serialized,
    )
    .expect("Should able to be deserialized into string");

    experimental_emit(output.0.key, output.0.value);
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Rebuild the plugin against the exact swc_core version shipped in your @swc/core release and redeploy
  2. Upgrade @swc/core and all swc plugins together in one coordinated change (check each plugin's peerDependencies)
  3. Temporarily disable plugins one by one to confirm which one emits the incompatible bytes
  4. If versions provably match, open an issue on swc-project/swc with the plugin wasm, @swc/core version, and a minimal repro

Example fix

# before
# @swc/core@1.3.100 (embeds swc_core X) + plugin built against swc_core X-3

# after
# in the plugin crate:
cargo update -p swc_core --precise <version matching @swc/core 1.3.100>
cargo build-wasi --release && cp target/wasm32-wasi/release/*.wasm ./
Defensive patterns

Strategy: validation

Validate before calling

// before loading plugins, verify the host runner can serve them
const semver = require('semver');
const coreVersion = require('@swc/core/package.json').version;
for (const [name] of swcConfig.jsc.experimental.plugins) {
  const peer = require(`${name}/package.json`).peerDependencies?.['@swc/core'];
  if (peer && !semver.satisfies(coreVersion, peer)) {
    throw new Error(`${name} requires @swc/core ${peer}, host has ${coreVersion}`);
  }
}

Try / catch

// Rust hosts embedding swc_plugin_runner can contain the panic:
let out = std::panic::catch_unwind(AssertUnwindSafe(|| transform_with_plugins()))
    .map_err(|_| anyhow::anyhow!("plugin emit output failed to decode; rebuild plugin against the host swc_core"));
// Node users: run plugin-enabled transforms in a worker/child process so a native panic cannot take down the main process

Prevention

When it happens

Trigger: A swc wasm plugin calls the emit host import while its guest bindings (swc_core version) do not match the swc_plugin_runner version embedded in the installed @swc/core; or the plugin returns malformed output_ptr/output_len.

Common situations: Upgrading @swc/core without rebuilding/reinstalling third-party plugins; plugins built from source with a stale Cargo.lock pinning an older swc_core; mixing plugin builds targeting wasm32-wasi with an incompatible host; custom plugins in a monorepo drifting from the app's @swc_core version.

Related errors


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