oven-sh/bun · error · Error
Unknown preprocessor macro ${name}
Error message
Unknown preprocessor macro ${name} What it means
The preprocessor rewrites every $-prefixed identifier in builtin JS to __intrinsic__<name> and then tries to interpret <name>( calls as known macros ($debug, $assert, $rust, $cpp, $newRustFunction, $newCppFunction, $isPromise*, $bindgenFn). Any other $-prefixed identifier followed by ( is treated as an unknown macro and fails the build.
Source
Thrown at src/codegen/replacements.ts:302
"[" +
inner.result
.slice(1, -1)
.replaceAll("'", '"')
.replace(/,[\s\n]*$/s, "") +
"]";
args = JSON.parse(str);
} catch {
throw new Error(`Call is not known at bundle-time: '$${name}${inner.result}'`);
}
if (args.length != 2 || typeof args[0] !== "string" || typeof args[1] !== "string") {
throw new Error(`$${name} takes two string arguments, but got '$${name}${inner.result}'`);
}
const id = registerNativeCall("bind", args[0], args[1], null);
return [slice.slice(0, match.index) + "__intrinsic__lazy(" + id + ")", inner.rest, true];
} else {
throw new Error("Unknown preprocessor macro " + name);
}
}
return [slice, rest, false];
}
/** Applies source code replacements as defined in `globalReplacements` */
export function applyGlobalReplacements(src: string) {
let result = src;
for (const replacement of globalReplacements) {
result = result.replace(replacement.from, replacement.toRaw ?? replacement.to!.replaceAll("$", "__intrinsic__"));
}
return result;
}
View on GitHub (pinned to 8c5296ac45)
Solutions
- Rename the helper so it does not start with $ — the $ prefix is reserved for preprocessor macros in src/js.
- If it is a genuine new macro, add its name to `function_replacements` in src/codegen/replacements.ts and implement its expansion branch in applyReplacements.
- Search src/js for `\$${name}(` to find the offending call site the message names.
Example fix
// before
function $fmt(s) { return s.trim(); }
$fmt(x);
// after
function fmt(s) { return s.trim(); }
fmt(x); Defensive patterns
Strategy: validation
Validate before calling
const knownMacros = new Set(["debug", "assert", "rust", "cpp", "newRustFunction", "newCppFunction", "isPromiseFulfilled", "isPromiseRejected", "isPromisePending", "bindgenFn"]);
for (const m of src.matchAll(/(?:^|[^a-zA-Z0-9_])\$([a-zA-Z0-9_]+)\s*\(/g)) {
if (!knownMacros.has(m[1])) throw new Error(`$${m[1]} is not a preprocessor macro; rename it to not start with $`);
} Prevention
- Reserve the $ prefix in src/js for preprocessor macros; name helpers without it.
- When adding a real macro, update function_replacements and the applyReplacements dispatch in the same commit.
- Lint for unknown $-identifiers so offenders surface before the bundler throws.
When it happens
Trigger: Defining or calling a helper whose name starts with $ inside src/js (e.g. `function $fmt(...)` then `$fmt(x)`), or adding a new intended macro without registering it in `function_replacements` in replacements.ts.
Common situations: Using jQuery-style $ naming conventions in builtin code; adding a new bundle-time macro but forgetting the registry list.
Related errors
- Call is not known at bundle-time: '$$${name}${inner.result}'
- Builtin Bundler: "${specifier}" cannot be imported from "${f
- Builtin Bundler: Could not resolve "${specifier}" in "${from
- $$${name} takes three arguments, but got '$$${name}${inner.r
- $$${name} takes two string arguments, but got '$$${name}${in
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/94f85271f8d316d8.
Report an issue: GitHub.