vercel/next.js · error
Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next
Error message
Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next build). What it means
Thrown by ensureNextBuilt (benchmark.ts:290) when packages/next/dist/bin/next (NEXT_BIN) is not accessible. The render-pipeline benchmark drives that binary directly to build and start the fixture, so it must exist locally. It cannot use a globally-installed `next` because it needs the locally-built framework (the whole point is benchmarking in-tree changes).
Source
Thrown at bench/render-pipeline/benchmark.ts:290
): Promise<void> {
const child = spawn(command, args, {
cwd,
env,
stdio: 'inherit',
})
const [code] = (await once(child, 'exit')) as [number | null]
if (code !== 0) {
throw new Error(
`Command failed: ${command} ${args.join(' ')} (exit ${code})`
)
}
}
async function ensureNextBuilt() {
try {
await access(NEXT_BIN)
} catch {
throw new Error(
`Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next build).`
)
}
}
async function waitForServerReady(
url: string,
timeoutMs: number,
serverDied?: () => boolean
): Promise<void> {
const start = performance.now()
while (performance.now() - start < timeoutMs) {
// Without this check, a server that dies on startup (e.g. EADDRINUSE
// against a stale server on the same port) is indistinguishable from
// a slow one — worse, a 200 from whatever else owns the port would
// pass, and the run would silently measure the wrong server.
if (serverDied?.()) {
throw new Error(View on GitHub (pinned to 0ae8c72462)
Solutions
- Build Next.js: `pnpm --filter=next build` (as the message says), then re-run the benchmark.
- On branch switch or fresh checkout, run a full bootstrap (pnpm install + pnpm build-all) per the repo's dev guide.
- Confirm the file exists: ls packages/next/dist/bin/next.
- If you intentionally only changed non-Next.js files, you still need a one-time build to produce NEXT_BIN.
Example fix
# before — error on benchmark start # Missing .../packages/next/dist/bin/next. Build Next.js first ... # fix pnpm --filter=next build pnpm bench:render-pipeline --scenario=e2e
Defensive patterns
Strategy: validation
Validate before calling
import { accessSync, constants } from 'node:fs'
import { resolve } from 'node:path'
const NEXT_BIN = resolve(REPO_ROOT, 'packages/next/dist/bin/next')
function ensureNextBuiltOrHint() {
try { accessSync(NEXT_BIN, constants.X_OK) }
catch {
throw new Error(`Missing ${NEXT_BIN}. Run: pnpm --filter=next build`)
}
} Type guard
import { existsSync } from 'node:fs'
function nextBinExists(bin: string): boolean {
return existsSync(bin)
} Try / catch
try {
await ensureNextBuilt()
} catch (err) {
console.error((err as Error).message)
console.error('Run: pnpm --filter=next build (or pnpm build-all for a full bootstrap)')
process.exit(2)
} Prevention
- Always run `pnpm --filter=next build` (or pnpm build-all) after checkout/branch-switch before benchmarking.
- Add a one-line bootstrap check at the start of CI scripts.
- Don't delete packages/next/dist between build and benchmark.
- Remember the benchmark needs the locally-built next, not a global install.
When it happens
Trigger: Calling runMinimalServerBenchmarks/runE2EBenchmarks (both call ensureNextBuilt first) when packages/next/dist/bin/next is absent — e.g. on a fresh checkout, after `git clean -fdx`, after switching branches without rebuilding, or when only a partial build ran.
Common situations: Fresh clone without bootstrap; branch switch that invalidated the dist output; `pnpm install` ran but `pnpm --filter=next build` did not; dist was deleted by a clean script.
Related errors
- Missing ${NEXT_BIN}. Build Next.js first (pnpm --filter=next
- Command failed: ${command} ${args.join(' ')} (exit ${code})
- Invalid numeric value for --${key}: ${value}
- --routes cannot be empty
- Each route must start with '/': ${route}
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/3119cab750bf2eb0.
Report an issue: GitHub.