vercel/turborepo · error · NpxTurboProcess
Failed to execute `turbo` via `npx`.
Error message
Failed to execute `turbo` via `npx`.
What it means
The shim's fallback path runs `npx turbo` when no usable local turbo exists; the spawn itself (runtime.child_spawner.spawn, run.rs:524 region) failed at the OS level and is wrapped as Error::NpxTurboProcess with the io::Error as #[source] (run.rs:114-115). Note the distinction: `which` failing to find npx is a separate Error::Which — this error means npx was found but exec'ing it failed.
Source
Thrown at crates/turborepo-shim/src/run.rs:524
raw_args.append(&mut shim_args.forwarded_args);
raw_args
}
fn spawn_child_turbo<R, C, S, V>(
runtime: &ShimRuntime<R, C, S, V>,
command: process::Command,
err: fn(std::io::Error) -> Error,
) -> ShimResult<R::Error>
where
R: TurboRunner,
C: ConfigProvider,
S: ChildSpawner,
V: VersionProvider,
{
let child: Arc<SharedChild> = match runtime.child_spawner.spawn(command) {
Ok(child) => child,
Err(e) => return ShimResult::ShimError(err(e)),
};
// The child turbo process shares our process group and will receive
// SIGINT directly from the kernel when the user presses Ctrl+C.
// Ignore SIGINT in the shim *after* spawning so the child inherits
// the default disposition (and can register its own handler), while
// the shim stays alive to collect the child's exit status.
#[cfg(unix)]
unsafe {
libc::signal(libc::SIGINT, libc::SIG_IGN);
}
let exit_status = match child.wait() {
Ok(status) => status,
Err(e) => return ShimResult::ShimError(err(e)),
};
let exit_code = exit_status.code().unwrap_or_else(|| {
debug!("child turbo failed to report exit code");View on GitHub (pinned to f9245100cf)
Solutions
- Run `npx turbo --version` manually and read the underlying errno — that is the #[source] of this error
- Reinstall Node/npm to regenerate the npx shim; check `head -1 $(which npx)` points at an existing node
- Install turbo locally in the repo so the shim uses the local binary and never needs the npx fallback
- Ensure PATH visible to spawned children includes the node bin directory
Example fix
# diagnose npx turbo --version head -1 "$(command -v npx)" # fix: regenerate shims / prefer local install npm install -g npm pnpm add -w -D turbo
Defensive patterns
Strategy: fallback
Validate before calling
// verify npx actually executes before relying on the fallback
let ok = std::process::Command::new("npx").arg("--version").status().map(|s| s.success()).unwrap_or(false);
if !ok { install_turbo_locally(); } Try / catch
// prefer local turbo; only fall back to npx, and surface the source errno
match run_local_turbo() {
ShimResult::ShimError(Error::LocalTurboProcess(_)) | Err(_) => {
match run_via_npx() {
ShimResult::ShimError(Error::NpxTurboProcess(src)) => handle_errno(src),
r => r,
}
}
r => r,
} Prevention
- Install turbo in the repo so the npx fallback never triggers
- After Node upgrades, regenerate npm shims (reinstall npm/node)
- Ensure the spawn environment's PATH contains the node bin dir
When it happens
Trigger: Spawning `npx turbo` fails with EACCES (npx shim not executable), ENOENT/ENOEXEC (Node was upgraded or moved so the shim's shebang `#!/usr/bin/env node` no longer resolves), or resource exhaustion (EMFILE).
Common situations: Node upgraded via nvm/system package and stale npm shims left behind Permissions broken on the global bin dir after a manual copy Running in minimal containers where env/node is absent from the spawn environment
Related errors
- Failed to execute local `turbo` process.
- `git ${args[0]}` failed: ${formatError(error)}
- no threads found for process {process_id}
- {message}
- {message}
AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17).
Data as JSON: /api/errors/a44d4f3a2a5efd3d.
Report an issue: GitHub.