Morganamilo/paru · critical
failed to spawn auth process
Error message
failed to spawn auth process
What it means
`LazyPipe::run` failed to spawn the external authentication helper process; the spawn failure is wrapped with context 'failed to spawn auth process' and then cached (memoized) in the lazy pipe, so every subsequent `run` call reuses the same failure. This typically means the auth binary path in Config is wrong, the binary is missing, or it failed at exec time.
Solutions
- Fix `spawn_auth`: verify the auth helper binary path in Config exists and is executable
- Run the helper manually with the same args to see the underlying spawn error
- Clear/replace the cached failure (recreate the LazyPipe) after fixing, since the Err is memoized
Example fix
// before
let pipe = pipe.get_or_insert_with(|| spawn_auth(config).context("failed to spawn auth process"));
// after
let pipe = match pipe.get_or_insert_with(|| spawn_auth(config).context("failed to spawn auth process")) {
Err(e) => bail!("auth process: {} (verify helper path in config)", e),
Ok(p) => p,
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the auth helper before first use
fn verify_auth_helper(config: &Config) -> Result<()> {
let path = config.auth_helper_path();
ensure!(Path::new(&path).exists(), "auth helper missing: {}", path);
ensure!(is_executable(&path), "auth helper not executable: {}", path);
Ok(())
} Try / catch
if let Err(e) = verify_auth_helper(&config) {
eprintln!("{}; falling back to interactive auth", e);
return interactive_auth(&config);
}
auth_pipe.run(&config).context("auth process")?; Prevention
- Check the helper binary exists and is executable at startup, not lazily
- Remember the failure is memoized — recreate the LazyPipe after fixing the environment
- Log the underlying spawn error, not just the context string
- Pin the helper path in config instead of relying on PATH
When it happens
Trigger: First call to `LazyPipe::run(config)` where `spawn_auth(config)` fails (auth executable not found, not executable, bad args). The error is stored in the `RefCell<Option<Result<...>>>`, so all later runs bail with `e.to_string()` — the original spawn error.
Common situations: Auth helper not built/installed before running; misconfigured path in Config; environment lacking PATH or permissions to execute the helper; after a package upgrade the binary moved.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
AI-assisted analysis of Morganamilo/paru@9ac3578807 (2026-09-12).
Data as JSON: /api/errors/08e33b7b90cebc01.
Report an issue: GitHub.
Appendix: source
Thrown at src/auth.rs:35
fn wait_ok(&mut self) -> Result<()> {
let mut buf = [0; "ok\n".len()];
self.read.read_exact(&mut buf)?;
ensure!(&buf == b"ok\n");
Ok(())
}
}
#[derive(Debug, Default)]
pub struct LazyPipe {
pipe: RefCell<Option<Result<Pipe>>>,
}
impl LazyPipe {
pub fn run(&self, config: &Config) -> Result<()> {
let mut pipe = self.pipe.borrow_mut();
let pipe = pipe.get_or_insert_with(|| spawn_auth(config).context("failed to spawn auth process"));
let pipe = match pipe {
Err(e) => bail!(e.to_string()),
Ok(p) => p,
};
loop {}
pipe.write.write_all(b"something")?;
pipe.wait_ok()?;
Ok(())
}
}
pub fn spawn_auth(config: &Config) -> Result<Pipe> {
let (paru_read, auth_write) = pipe()?;
let (auth_read, paru_write) = pipe()?;
/*Command::new(&config.sudo_bin)
.args(&config.sudo_flags)
.arg(std::env::current_exe()?)
.arg("--authpipe")View on GitHub (pinned to 9ac3578807)