oven-sh/bun · error · Error
${loc}: HOST_EXPORT(${e.symbol}, rust) param `${p.raw}` is a
Error message
${loc}: HOST_EXPORT(${e.symbol}, rust) param `${p.raw}` is a reference; use a raw pointer What it means
For hooks declared `HOST_EXPORT(symbol, rust)`, the generator forwards the signature verbatim into an `#[unsafe(no_mangle)] pub extern "Rust" fn` item. Reference parameters are rejected because an extern "Rust" fn item requires explicit lifetimes for borrowed types, which the generator does not synthesize. The fix is always the same: take a raw pointer (`*const T` / `*mut T`) at the ABI boundary and dereference inside.
Source
Thrown at src/codegen/generate-host-exports.ts:422
// `SYSV_ABI` lazyPropCb-style getters). `&JSGlobalObject` is
// ABI-identical to non-null `*const JSGlobalObject`; C++ never passes
// null here.
const body = retIsJsResult
? ` host_fn::host_fn_lazy(g, ${impl})`
: ` host_fn::host_fn_lazy_passthrough(g, ${impl})`;
return `
// ${loc}
${emitNoMangle(e.abi, e.symbol, "g: &JSGlobalObject", "JSValue", body)}`;
}
case "rust": {
// `extern "Rust"` link-time hook: forward the safe signature verbatim
// (no pointer rewriting; `extern "Rust"` ABI == native Rust ABI).
// Reference params/returns are rejected — `extern "Rust" fn` items need
// explicit lifetimes for borrowed types and the generator does not
// synthesise them. Use raw pointers in the impl signature instead.
for (const p of e.params)
if (p.ty.startsWith("&"))
throw new Error(
`${loc}: HOST_EXPORT(${e.symbol}, rust) param \`${p.raw}\` is a reference; use a raw pointer`,
);
if (e.ret.startsWith("&"))
throw new Error(
`${loc}: HOST_EXPORT(${e.symbol}, rust) return type \`${e.ret}\` is a reference; use a raw pointer`,
);
const sig = e.params.map(p => `${p.name}: ${p.ty}`).join(", ");
const call = e.params.map(p => p.name).join(", ");
return `
// ${loc}
#[allow(dead_code, unreachable_pub, unused)]
#[unsafe(no_mangle)]
pub extern "Rust" fn ${e.symbol}(${sig}) -> ${e.ret} {
${impl}(${call})
}`;
}
case "generic": {
const sig = e.params.map(p => `${p.name}: ${p.cTy}`).join(", ");View on GitHub (pinned to 8c5296ac45)
Solutions
- Change each reference parameter to a raw pointer: `&T` → `*const T`, `&mut T` → `*mut T`
- Reborrow inside the body: `let r = unsafe { &*ptr };` (or use the established Bun helpers for JSGlobalObject pointers)
- If the hook must stay reference-typed, use the `jsc` or `c` variant, which go through a generated thunk that rewrites pointers
Example fix
// before
// HOST_EXPORT(BunOnHook, rust)
pub fn on_hook(global: &JSGlobalObject, cb: &JSValue) { ... }
// after
// HOST_EXPORT(BunOnHook, rust)
pub fn on_hook(global: *const JSGlobalObject, cb: *const JSValue) { ... } Defensive patterns
Strategy: validation
Validate before calling
// reject reference params on HOST_EXPORT(..., rust) hooks
import { Glob } from "bun";
for (const f of new Glob("src/**/*.rs").scanSync(".")) {
const text = await Bun.file(f).text();
const re = /\/\/\s*HOST_EXPORT\(\s*(\w+)\s*,\s*rust\s*\)[^;]*?pub\s+fn\s+\1\s*\(([^)]*)\)/gs;
for (const m of text.matchAll(re)) {
if (m[2].split(",").some(p => p.trim().replace(/^[\w\s]+:\s*/, "").startsWith("&"))) {
throw new Error(`${f}: rust hook ${m[1]} takes a reference — use a raw pointer`);
}
}
} Type guard
function isRawPointerTy(ty: string): boolean {
return !ty.trim().startsWith("&");
} Prevention
- Reserve reference-typed signatures for the jsc/c HOST_EXPORT variants that generate pointer-rewriting thunks
- For rust-linkage hooks, default to `*const T`/`*mut T` params and deref inside the body
When it happens
Trigger: Writing `// HOST_EXPORT(MyHook, rust)` above a `pub fn` whose parameters include `&JSGlobalObject`, `&str`, `&T`, or `&mut T`.
Common situations: Adding new link-time Rust hooks (the `rust` linkage variant, as opposed to `jsc`/`c`) and copying the safe signature from a regular function; the jsc/c variants tolerate references because thunks are generated, the rust variant does not.
Related errors
- ${loc}: HOST_EXPORT(${e.symbol}, rust) return type `${e.ret}
- slice/str param `${ty}` is not FFI-safe; pass (ptr, len)
- ${where}: cannot parse param `${raw}`
- generate-string-map: duplicate key ${JSON.stringify(k)} in $
- Call is not known at bundle-time: '$$${name}${inner.result}'
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/a8b1cd34a48b8874.
Report an issue: GitHub.