gastownhall/beads · error
fork child: %w
Error message
fork child: %w
What it means
The library failed to fork/exec the proxy child process (forkExecChild). This wraps the OS-level spawn failure — binary missing, exec format or permission problem, or resource limits — after the lock and quarantine steps already succeeded. Everything spawned so far is cleaned up (handoff flag, marker, lock) before returning.
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:338
currentEpoch, err := readStopEpoch(rootDir)
if err != nil {
return Endpoint{}, fmt.Errorf("read proxy stop epoch under lock: %w", err)
}
if currentEpoch != stopEpoch {
return Endpoint{}, fmt.Errorf("%w for %s", errStartInterrupted, rootDir)
}
if err := quarantineForSpawn(rootDir, discovery); err != nil {
return Endpoint{}, err
}
if err := cleanupOrphanBackend(rootDir); err != nil {
return Endpoint{}, err
}
handedOff = true
child, err := forkExecChild(rootDir, opts, opts.Port, stopEpoch, lock)
if err != nil {
return Endpoint{}, fmt.Errorf("fork child: %w", err)
}
defer func() { _ = clearOwnSpawnMarker(rootDir, child.marker) }()
defer func() {
if child.handle != nil {
_ = child.handle.Close()
}
}()
hard := time.NewTimer(spawnReadyHardTimeout)
defer hard.Stop()
poll := time.NewTicker(openPollInterval)
defer poll.Stop()
for {
discovered := readAndDial(rootDir)
if discovered.status == adoptionAdopted {
if err := sweepOldQuarantines(rootDir, time.Now()); err != nil {
log.Printf("dbproxy: could not sweep old quarantined records in %s: %v", rootDir, err)View on GitHub (pinned to 71377f2769)
Solutions
- Verify the configured binary path exists and is executable: ls -l $(DoltBinPath) and try running it directly
- Check the mount is not noexec (mount output) and fix the binary location
- Raise limits (ulimit -u, cgroup pids.max) if fork fails under load
- Reinstall/upgrade bd so the bundled paths match the current version
Example fix
// before
opts.DoltBinPath = "/usr/local/bin/dolt" // binary removed by upgrade
// error: fork child: fork/exec /usr/local/bin/dolt: no such file or directory
// after
if _, err := os.Stat(opts.DoltBinPath); err != nil {
opts.DoltBinPath = "/opt/bd/bin/dolt" // re-point at the real binary
}
ep, err := proxy.GetCreateDatabaseProxyServerEndpoint(root, opts) Defensive patterns
Strategy: validation
Validate before calling
// Verify the spawn binary before opening
if opts.DoltBinPath != "" {
if fi, err := os.Stat(opts.DoltBinPath); err != nil || fi.IsDir() || fi.Mode().Perm()&0o100 == 0 {
return fmt.Errorf("spawn binary missing or not executable: %s", opts.DoltBinPath)
}
} Prevention
- Resolve DoltBinPath at startup and fail fast if absent
- Keep binaries on exec-permitted mounts (not noexec)
- Pin binary versions with bd upgrades; re-check paths after upgrades
- Watch ulimit/pids limits in sandboxes
When it happens
Trigger: forkExecChild(rootDir, opts, opts.Port, stopEpoch, lock) fails during spawnAndHandoff: opts.DoltBinPath (or the proxy entrypoint binary) does not exist or is not executable, exec fails due to ENOEXEC/EACCES, or fork hits resource limits (ulimit, PID exhaustion).
Common situations: bd upgraded/downgraded and the configured DoltBinPath points to an old or removed binary; container images missing the dolt binary; noexec mount on the binary's filesystem; hitting process limits in CI sandboxes.
Related errors
- dolt version probe failed
- child exited without reporting an error
- pidfile: invalid pid
- ErrUnverifiableProcess
- bd %s: %w: %s
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5e769013b5f86ade.
Report an issue: GitHub.