swc-project/swc · error · napi::Error
GenericFailure
GenericFailure
Error message
{err:?} What it means
swc_nodejs_common is the shared plumbing for SWC's Node.js (napi) bindings. Its `MapErr` trait converts any `anyhow::Error` into a `napi::Error` with `Status::GenericFailure`, formatting the entire anyhow error chain with `{:?}` (crates/swc_nodejs_common/src/lib.rs:12). It is the single funnel for failures crossing the Rust→JS boundary — including `get_deserialized`, which serde-deserializes a buffer passed from JavaScript — so on the JS side you only see code 'GenericFailure' plus the debug string.
Source
Thrown at crates/swc_nodejs_common/src/lib.rs:12
#![deny(warnings)]
use std::any::type_name;
use anyhow::Context;
use napi::Status;
use serde::de::DeserializeOwned;
pub trait MapErr<T>: Into<Result<T, anyhow::Error>> {
fn convert_err(self) -> napi::Result<T> {
self.into()
.map_err(|err| napi::Error::new(Status::GenericFailure, format!("{err:?}")))
}
}
impl<T> MapErr<T> for Result<T, anyhow::Error> {}
pub fn get_deserialized<T, B>(buffer: B) -> napi::Result<T>
where
T: DeserializeOwned,
B: AsRef<[u8]>,
{
let mut deserializer = serde_json::Deserializer::from_slice(buffer.as_ref());
deserializer.disable_recursion_limit();
let v = T::deserialize(&mut deserializer)
.with_context(|| {
format!(
"Failed to deserialize buffer as {}\nJSON: {}",
type_name::<T>(),View on GitHub (pinned to 5176682b65)
Solutions
- Read the {err:?} text — for serde failures it names the exact field and expected type
- Align the JS-side options object with the interface the installed binding version expects
- Ensure the native module and the JS package versions match (rebuild/reinstall node_modules)
- Log the exact payload right before the call and validate its shape against the binding's schema
Example fix
// before
const res = await transformFn(id, { soruceType: 'module' }); // typo → serde error → GenericFailure
// after
const res = await transformFn(id, { sourceType: 'module' }); Defensive patterns
Strategy: try-catch
Validate before calling
// JS side: validate the payload shape before calling the native binding
function validateTransformOpts(opts) {
const known = new Set(['sourceType', 'filename', 'jsc', 'module', 'isModule', 'minify', 'sourceMaps', 'inlineSourcesContent', 'parser']);
for (const key of Object.keys(opts || {})) if (!known.has(key)) throw new Error(`unknown option: ${key}`);
if ('sourceType' in (opts || {}) && !['module', 'script', 'unambiguous'].includes(opts.sourceType)) throw new Error('bad sourceType');
} Type guard
// Narrow a caught error to a napi GenericFailure from the Rust binding
function isNapiGenericFailure(e: unknown): e is Error & { code: 'GenericFailure' } {
return e instanceof Error && (e as any).code === 'GenericFailure';
} Try / catch
try {
const out = await nativeTransform(id, code, opts);
} catch (e) {
if (isNapiGenericFailure(e)) {
// e.message is the Rust-side {err:?} debug string; parse the serde path from it
console.error('binding failure:', e.message);
}
throw e;
} Prevention
- Type the JS options object against the binding's .d.ts instead of hand-rolling payloads
- Keep @swc/* JS packages and native binaries in lockstep (dedupe, reinstall after upgrades)
- Log the exact arguments on failure so the {err:?} serde path maps to a concrete field
- Treat any GenericFailure as an internal binding error — do not retry blindly; fix the payload or versions
When it happens
Trigger: Calling a Node binding whose Rust body returns Err: `get_deserialized::<T, _>(&buffer)` fails when the JS-passed payload does not deserialize into the expected type (wrong field names/types, malformed JSON), or any internal anyhow error passed through `.convert_err()` in the binding wrapper.
Common situations: Passing an options object with a typo'd or renamed field from JS (serde mismatch); version skew between the JS wrapper package and the native module; passing a string where bytes are expected; empty or truncated buffers after a failed fetch/transform.
Related errors
- Invalid attempt to iterate non-iterable instance. In order t
- Duplicated methods (${element.key}) can't be decorated.
- Decorators can't be placed on different accessors with for t
- #[ast_serde] on enum does not accept any argument
- jsonify: Expr {:?} cannot be converted to json
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/f91f7cf894674b2c.
Report an issue: GitHub.