parcel-bundler/parcel · error · napi::Error
GenericFailure
GenericFailure
Error message
Could not convert value returned from macro to AST.
What it means
Returned (as a napi::Error of Status::GenericFailure) by @parcel/macros when napi_to_js_value receives a value whose ValueType is Symbol, External, or Unknown. The macro system can round-trip undefined/null/number/boolean/string/array/object/regex/function, but has no AST representation for these three types, so conversion fails and the error propagates to the JS caller.
Source
Thrown at crates/macros/src/napi.rs:165
let names = obj.get_property_names()?;
let len = names.get_array_length()?;
let mut props = IndexMap::with_capacity(len as usize);
for i in 0..len {
let prop = names.get_element::<JsString>(i)?;
let name = prop.into_utf8()?.into_owned()?;
let value = napi_to_js_value(obj.get_property(prop)?, env)?;
props.insert(name, value);
}
Ok(JsValue::Object(props))
}
}
ValueType::Function => {
let f = unsafe { value.cast::<JsFunction>() };
let source = f.coerce_to_string()?.into_utf8()?.into_owned()?;
Ok(JsValue::Function(source))
}
ValueType::Symbol | ValueType::External | ValueType::Unknown => Err(napi::Error::new(
napi::Status::GenericFailure,
"Could not convert value returned from macro to AST.",
)),
}
}
fn await_promise(
env: Env,
result: JsUnknown,
tx: Sender<Result<JsValue, MacroError>>,
) -> napi::Result<()> {
// If the result is a promise, wait for it to resolve, and send the result to the channel.
// Otherwise, send the result immediately.
if result.is_promise()? {
let result: JsObject = result.try_into()?;
let then: JsFunction = result.get_named_property("then")?;
let tx2 = tx.clone();
let cb = env.create_function_from_closure("callback", move |ctx| {View on GitHub (pinned to 59484858a1)
Solutions
- Ensure the macro returns only plain JSON-representable data (strings, numbers, booleans, arrays, plain objects, regexes, functions-as-source).
- Strip or stringify any Symbol-keyed/valued properties before returning.
- Avoid returning native/external handles; serialize the data you need first.
Example fix
// before
export default function macro() {
return { id: Symbol('x') };
}
// after
export default function macro() {
return { id: 'x' };
} Defensive patterns
Strategy: type-guard
Validate before calling
function sanitizeForAst(v) {
if (typeof v === 'symbol') throw new Error('Cannot return Symbol from macro');
if (Array.isArray(v)) return v.map(sanitizeForAst);
if (v && typeof v === 'object') {
const out = {};
for (const [k, val] of Object.entries(v)) out[k] = sanitizeForAst(val);
return out;
}
return v;
} Type guard
function isMacroSafeValue(v, seen = new WeakSet()) {
if (typeof v === 'symbol') return false;
if (v === null || typeof v !== 'object') return true;
if (seen.has(v)) return false;
seen.add(v);
return Object.getOwnPropertySymbols(v).length === 0 &&
Object.values(v).every(x => isMacroSafeValue(x, seen));
} Try / catch
try {
result = macro(...args);
} catch (e) {
if (/Could not convert value returned from macro/.test(e?.message)) {
throw new Error('Macro returned a Symbol/External/Unknown value; serialize it first.');
}
throw e;
} Prevention
- Return only plain JSON-serializable data plus regex/function values from macros.
- Strip Symbol keys/values before returning.
- Avoid passing native handles or class instances through macro boundaries.
When it happens
Trigger: A Parcel macro (JS function invoked during transform) returns a value that contains, at any depth, a Symbol, a napi External (native pointer), or a value Node reports as Unknown.
Common situations: Macro returns an object with a Symbol-keyed property or a Symbol value (e.g. Symbol.for('x')), returns a class instance whose prototype chain exposes a Symbol, or returns an object embedding a native handle (Buffer internals, FFI).
Related errors
- GenericFailure
- Asset has an AST but no generate method is available on the
- Cannot call getCode() on an asset with a dirty AST. For tran
- ${pluginName} does not have a generate method
- Library targets are not supported in serve mode.
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/4ee87079b49f439a.
Report an issue: GitHub.