oven-sh/bun · error · Error
${nm} failed on ${bunProfile} ${r.stderr}
Error message
${nm} failed on ${bunProfile}
${r.stderr} What it means
While reading the unstripped bun-profile binary's symbol table, nm exited non-zero and its stderr is appended to the message. This is a tool/format-level failure — nm ran but refused or failed to parse the file — distinct from spawn errors (167) and from finding zero symbols (169).
Source
Thrown at scripts/orderfile/generate.ts:141
/** Fail if fewer than this many functions were traced. */
minFunctions?: number;
/** Print per-workload progress. */
verbose?: boolean;
}
/**
* Linker-visible function names, by address. Multiple names can share one
* address (aliases, and ICF on darwin), and the order file must list every name
* the linker might know a function by. On macOS nm prints names with the C
* leading underscore, which is also what `-order_file` expects, so no
* stripping — lld and ld take exactly what nm gave.
*/
function readSymbolTable(bunProfile: string): Map<number, string[]> {
// Bare `nm` with no GNU-only long options: the regex below is the
// defined-text-symbol filter, and nothing here depends on output order.
const nm = process.env.NM || "nm";
const r = runCommand([nm, bunProfile]);
if (r.status !== 0) throw new Error(`${nm} failed on ${bunProfile}\n${r.stderr}`);
const symbols = new Map<number, string[]>();
for (const line of r.stdout.toString().split("\n")) {
const m = /^([0-9a-f]+) ([tT]) (\S+)$/.exec(line);
if (!m) continue;
const address = parseInt(m[1]!, 16);
const names = symbols.get(address);
if (names) names.push(m[3]!);
else symbols.set(address, [m[3]!]);
}
if (symbols.size === 0) throw new Error(`${nm} reported no text symbols — is ${bunProfile} stripped?`);
return symbols;
}
/** Write function starts for functrace.c: u64 magic, version, count, addresses. */
function writeStarts(path: string, addresses: number[]): void {
const buffer = new ArrayBuffer((STARTS_HEADER_WORDS + addresses.length) * 8);
const words = new BigUint64Array(buffer);View on GitHub (pinned to 8c5296ac45)
Solutions
- Read the appended stderr — it names the parse problem
- Check the file: `file <buildDir>/bun-profile` and confirm it matches the host format
- Point NM at the platform-correct nm or unset the NM override so the default is used
- Rebuild the binary (`bun run build:release`) if the file is corrupt or truncated
Example fix
# before $ NM=llvm-nm-15 bun scripts/orderfile/generate.ts Error: llvm-nm-15 failed on build/bun-profile ... # after — use the default platform nm $ env -u NM bun scripts/orderfile/generate.ts
Defensive patterns
Strategy: try-catch
Validate before calling
import { spawnSync } from "node:child_process";
const probe = spawnSync(process.env.NM || "nm", ["--version"]);
if (probe.error || probe.status !== 0) {
throw new Error("nm is missing or broken — fix NM/PATH before generating the order file");
} Try / catch
try {
return readSymbolTable(bunProfile);
} catch (err) {
if (/failed on .*\n/.test(String(err))) {
console.error(`nm could not parse ${bunProfile} — verify format/arch or set NM`);
}
throw err;
} Prevention
- Use the nm that ships with the platform's default toolchain; avoid mixing LLVM and GNU nm across cross-builds
- Regenerate the build rather than tracing half-written artifacts after cancelled builds
When it happens
Trigger: The NM env var (or bare `nm`) resolves to an nm that cannot parse the binary's object format (e.g. LLVM nm vs GNU nm disagreements, wrong-arch nm); the binary is truncated or corrupt from an interrupted build.
Common situations: Cross-compilation environments where the default nm targets another platform; Nix/conda shims shadowing binutils nm; partial build artifacts after a cancelled `bun run build:release`.
Related errors
- ${nm} reported no text symbols — is ${bunProfile} stripped?
- ${options.label ?? cmd[0]}: ${r.error.message}
- workload "${name}" wrote a truncated trace
- failed to build the tracer with ${cc} ${build.stderr}
- failed to build the pty runner with ${cc} ${pty.stderr}
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/5d51093c6abf6cd6.
Report an issue: GitHub.