epi052/feroxbuster · critical

failed to spawn a child process

Error message

failed to spawn a child process

What it means

wrapped_main spawns a helper child process (a binary) with tokio::process::Command to stream output. Command::spawn().expect(...) panics if the OS cannot spawn the child, producing 'failed to spawn a child process'.

Solutions

  1. Ensure the child binary exists and is executable at the resolved path (chmod +x)
  2. Raise container/sandbox rlimits (e.g. ulimit -u, docker --pids-limit) or allow process spawning in your security policy
  3. Check for PID exhaustion (too many processes) and free resources, then rerun

Example fix

// before (shell)
./feroxbuster # not executable / noexec volume
// after (shell)
chmod +x ./feroxbuster && ./feroxbuster
Defensive patterns

Strategy: retry

Validate before calling

let bin_ok = std::path::Path::new(&bin).exists();
let can_exec = bin_ok && std::fs::metadata(&bin).map(|m| m.permissions().readonly() == false).unwrap_or(false);

Type guard

fn spawnable(bin: &str) -> bool { std::path::Path::new(bin).exists() }

Try / catch

match Command::new(&bin).args(&args).stdout(Stdio::piped()).spawn() {
  Ok(child) => stream(child),
  Err(e) => eprintln!("spawn failed ({e}); check binary path/permissions/limits"),
}

Prevention

When it happens

Trigger: Calling wrapped_main when the resolved child binary cannot be executed: binary missing at that path, missing execute permission, exec hitting resource limits (fork/ENOMEM, pid limits), or a seccomp/container policy blocking exec.

Common situations: Running inside minimal Docker images with restricted rlimits, sandboxed CI runners blocking process creation, or the binary having been moved/deleted while running.

Related errors


AI-assisted analysis of epi052/feroxbuster@1f595dab5c (2026-09-13). Data as JSON: /api/errors/41cc5e0415f5f530. Report an issue: GitHub.

Appendix: source

Thrown at src/main.rs:484

                cloned[out_idx + 1] = full_path;
            }

            cloned.push("-u".to_string());
            cloned.push(target);

            let bin = cloned.index(0).to_owned(); // user's path to feroxbuster
            let args = cloned.index(1..).to_vec(); // and args

            let permit = PARALLEL_LIMITER.acquire().await?;

            log::debug!("parallel exec: {} {}", bin, args.join(" "));

            tokio::task::spawn(async move {
                let mut output = Command::new(bin)
                    .args(&args)
                    .stdout(Stdio::piped())
                    .spawn()
                    .expect("failed to spawn a child process");

                let stdout = output.stdout.take().unwrap();

                let mut bufread = BufReader::new(stdout);
                // output for a single line is a minimum of 51 bytes, so we'll start with that
                // + a little wiggle room, and grow as needed
                let mut buf: String = String::with_capacity(128);

                while let Ok(n) = bufread.read_line(&mut buf) {
                    if n > 0 {
                        let trimmed = buf.trim();
                        if !trimmed.is_empty() {
                            println!("{trimmed}");
                        }
                        buf.clear();
                    } else {
                        break;
                    }

View on GitHub (pinned to 1f595dab5c)