oven-sh/bun · error · Error

failed to build the pty runner with ${cc} ${pty.stderr}

Error message

failed to build the pty runner with ${cc}
${pty.stderr}

What it means

Compiling ptyrun.c — the pseudo-terminal runner that executes interactive workloads under a real tty — failed, with compiler stderr appended. On Linux it additionally links -lutil for the pty APIs, so a missing util library is a platform-specific cause.

Source

Thrown at scripts/orderfile/generate.ts:211

  const bunProfile = join(buildDir, options.exeName ?? "bun-profile");
  if (!existsSync(bunProfile)) {
    throw new Error(`${bunProfile} not found — build it first (bun run build:release)`);
  }

  const scratch = mkdtempSync(join(tmpdir(), "bun-orderfile-"));
  try {
    // ── Build the tracer and the pty runner ───────────────────────────────────
    const tracer = join(scratch, darwin ? "functrace.dylib" : "functrace.so");
    const ptyrun = join(scratch, "ptyrun");
    const cc = process.env.CC || "cc";
    const build = runCommand(
      darwin
        ? [cc, "-O2", "-dynamiclib", "-fPIC", "-o", tracer, join(here, "functrace.c")]
        : [cc, "-O2", "-shared", "-fPIC", "-o", tracer, join(here, "functrace.c"), "-ldl", "-lpthread"],
    );
    if (build.status !== 0) throw new Error(`failed to build the tracer with ${cc}\n${build.stderr}`);
    const pty = runCommand([cc, "-O2", "-o", ptyrun, join(here, "ptyrun.c"), ...(darwin ? [] : ["-lutil"])]);
    if (pty.status !== 0) throw new Error(`failed to build the pty runner with ${cc}\n${pty.stderr}`);

    // ── Symbol table and function starts ──────────────────────────────────────
    const symbols = readSymbolTable(bunProfile);
    const startsPath = join(scratch, "starts.bin");
    writeStarts(
      startsPath,
      [...symbols.keys()].sort((a, b) => a - b),
    );

    // ── Representative workloads ──────────────────────────────────────────────
    // Order matters: earlier workloads get the densest placement, so the plain
    // runtime startup path comes first.
    const fixtures = join(scratch, "fixtures");
    mkdirSync(join(fixtures, "tests"), { recursive: true });
    writeFileSync(
      join(fixtures, "hello.ts"),
      `const greet = (name: string): string => \`hi \${name}\`;\nconsole.log(greet("world"));\n`,
    );

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Read the appended stderr — it distinguishes a missing -lutil from a compile error
  2. Install/repair the C toolchain (build-essential / Xcode CLT) including libc dev pieces
  3. Set CC to a known-good compiler and re-run; scratch rebuilds are cheap
Defensive patterns

Strategy: try-catch

Validate before calling

import { spawnSync } from "node:child_process";

// Probe both compilations cheaply before the full run.
const probe = spawnSync(cc, ["-O2", "-o", "/tmp/ptyrun-probe", "ptyrun.c", ...(darwin ? [] : ["-lutil"])], { cwd: here });
if (probe.status !== 0) throw new Error(`pty runner would fail to build:\n${probe.stderr}`);

Try / catch

try {
  buildPtyRunner();
} catch (err) {
  if (/failed to build the pty runner/.test(String(err))) {
    console.error("Check -lutil availability on Linux and the C toolchain; stderr above names the cause");
  }
  throw err;
}

Prevention

When it happens

Trigger: Same toolchain problems as the tracer build (no compiler, bad CC), plus on Linux a missing/unavailable libutil; on macOS an SDK mismatch affecting pty headers.

Common situations: Minimal containers lacking libc development files; broken CC overrides; toolchain half-installed so functrace.c compiled but ptyrun.c did not.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/135affca2e98c6f4. Report an issue: GitHub.