oven-sh/bun · error · Error
$$${name} takes three arguments, but got '$$${name}${inner.r
Error message
$$${name} takes three arguments, but got '$$${name}${inner.result}' What it means
$newRustFunction/$newCppFunction create native function objects at bundle time and require exactly three literal arguments: (structName: string, functionName: string, length: number). The arity/type check runs after JSON parsing succeeds, so this error means the call parsed but did not match that shape.
Source
Thrown at src/codegen/replacements.ts:258
const str =
"[" +
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 != (is_create_fn ? 3 : 2) ||
typeof args[0] !== "string" ||
typeof args[1] !== "string" ||
(is_create_fn && typeof args[2] !== "number")
) {
if (is_create_fn) {
throw new Error(`$${name} takes three arguments, but got '$${name}${inner.result}'`);
} else {
throw new Error(`$${name} takes two string arguments, but got '$${name}${inner.result}'`);
}
}
const id = registerNativeCall(kind, args[0], args[1], is_create_fn ? args[2] : null);
return [slice.slice(0, match.index) + "__intrinsic__lazy(" + id + ")", inner.rest, true];
} else if (name === "isPromiseFulfilled" || name === "isPromiseRejected" || name === "isPromisePending") {
const inner = sliceSourceCode(rest, true);
// JSC::JSPromise::Status: Pending = 0, Fulfilled = 1, Rejected = 2.
const status = name === "isPromisePending" ? 0 : name === "isPromiseFulfilled" ? 1 : 2;
let args;
if (debug) {
// use a property on @lazy as a temporary holder for the expression. only in debug!
args = `($assert(__intrinsic__isPromise(__intrinsic__lazy.temp=${inner.result.slice(0, -1)}))),__intrinsic__peekPromiseStatus(__intrinsic__lazy.temp) === (__intrinsic__lazy.temp = undefined, ${status}))`;
} else {
args = `(__intrinsic__peekPromiseStatus${inner.result} === ${status})`;View on GitHub (pinned to 8c5296ac45)
Solutions
- Supply all three literals: $newRustFunction("MyStruct", "myFn", 2).
- Make the third argument a plain number literal (not "2" and not a variable).
- If you only need an existing function, use $rust/$cpp (two string args) instead of the new* form.
Example fix
// before
const fn = $newRustFunction("MyStruct", "myFn");
// after
const fn = $newRustFunction("MyStruct", "myFn", 2); Defensive patterns
Strategy: validation
Validate before calling
const newFnRe = /\$new(Rust|Cpp)Function\((.*?)\)/g;
for (const m of src.matchAll(newFnRe)) {
const args = m[2].split(",").map(s => s.trim());
const ok = args.length === 3 && /^(['"]).*\1$/.test(args[0]) && /^(['"]).*\1$/.test(args[1]) && /^\d+$/.test(args[2]);
if (!ok) throw new Error(`bad $new${m[1]}Function call: ${m[0]}`);
} Prevention
- Memorize the shapes: $newRustFunction/$newCppFunction(string, string, number); $rust/$cpp(string, string).
- Prefer copy-pasting an existing correct call site and editing names only.
When it happens
Trigger: Calling $newRustFunction with two arguments (copying a $rust call site), passing the argument count as a string, or adding a trailing fourth argument.
Common situations: Copy-pasting a $rust(...) binding and just renaming the macro; updating a binding signature and forgetting the length parameter.
Related errors
- $$${name} takes two string arguments, but got '$$${name}${in
- Call is not known at bundle-time: '$$${name}${inner.result}'
- slice/str param `${ty}` is not FFI-safe; pass (ptr, len)
- ${where}: cannot parse param `${raw}`
- ${loc}: HOST_EXPORT(${e.symbol}, rust) param `${p.raw}` is a
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/d3543bcdafc92f16.
Report an issue: GitHub.