gastownhall/beads · error
start proxy child: %w
Error message
start proxy child: %w
What it means
This error is wrapped in forkExecChild (called from spawnAndHandoff) when exec.Command.Start() fails to launch the detached dbproxy child process. cmd.Start() performs fork/exec and also fails if the binary is missing, not executable, or the process cannot be created; the log file and spawn marker are cleaned up before returning.
Source
Thrown at internal/storage/dbproxy/proxy/endpoint.go:529
released = true
lock.Unlock()
beforeProxyChildStart()
// GH#4634: same hazard as the direct sql-server spawn, one hop further
// out. The proxy child is detached and long-lived, and it starts the
// sql-server itself, so a caller's non-CLOEXEC descriptor would otherwise
// be inherited twice over and pinned for the proxy's whole lifetime.
if leaked := fdhygiene.MarkInheritedCloexec(); len(leaked) > 0 {
// debug.Logf, not log.Printf: this fires in normal operation whenever
// the caller's environment leaves any fd open, and the parent's stderr
// may be parsed script output.
debug.Logf("dbproxy: marked %d inherited fd(s) close-on-exec before starting proxy child: %v", len(leaked), leaked)
}
if err := cmd.Start(); err != nil {
_ = logFile.Close()
_ = clearOwnSpawnMarker(rootDir, marker)
return nil, fmt.Errorf("start proxy child: %w", err)
}
done := make(chan error, 1)
go func() {
waitErr := cmd.Wait()
_ = logFile.Close()
done <- waitErr
close(done)
}()
// Theoretical race: the birth token is captured after Start, so the child
// could exit and its PID be recycled before Capture runs, making the
// handle describe the unrelated replacement. The window is a few
// milliseconds against OS PID-reuse latency, and the OS has no primitive
// to atomically capture identity at spawn, so this is accepted and
// documented rather than defended.
var handle *procid.Handle
childBirth, captureErr := procid.Capture(cmd.Process.Pid)View on GitHub (pinned to 71377f2769)
Solutions
- Verify the running binary still exists and is executable (ls -l /proc/self/exe; re-run bd after reinstalling)
- Check process limits: ulimit -u, cgroup pids.max; raise or free processes
- Check disk space and filesystem mount flags (noexec/read-only) for the executable and log file directory
- Retry the command; if persistent, inspect the underlying error (os.StartProcess / fork errno) printed with %w
Example fix
// before
if err := cmd.Start(); err != nil {
return nil, fmt.Errorf("start proxy child: %w", err)
}
// after
if err := cmd.Start(); err != nil {
var le *os.LinkError
if errors.As(err, &le) {
return nil, fmt.Errorf("start proxy child (binary %q, errno %v): %w", le.Name, le.Err, err)
}
return nil, fmt.Errorf("start proxy child: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
self, _ := os.Executable()
if fi, err := os.Stat(self); err != nil || fi.Mode()&0o111 == 0 {
return fmt.Errorf("cannot spawn proxy: executable %q missing or not executable", self)
} Try / catch
spawned, err := spawnAndHandoff(root)
if err != nil && strings.HasPrefix(err.Error(), "start proxy child:") {
var le *os.LinkError
if errors.As(err, &le) { /* inspect le.Err: EACCES/EAGAIN/ENOENT */ }
// wait briefly and retry once
} Prevention
- Avoid replacing the binary while bd is running (install upgrades atomically via rename)
- Keep process limits (ulimit -u, cgroup pids.max) comfortably above concurrent bd usage
- Ensure the workspace log file directory exists and is writable before spawning
- Keep the binary on a filesystem without noexec/read-only restrictions
When it happens
Trigger: spawnAndHandoff attempts to start the proxy child after releasing proxy.lock; cmd.Start() fails because the current executable (self) cannot be fork/exec'd or system process limits are exhausted.
Common situations: The bd binary was deleted or replaced (upgraded in place) between detection and spawn; EAGAIN from hitting RLIMIT_NPROC / cgroup process limits; tmpdir or exec resources unavailable; read-only or noexec filesystem preventing exec; permission denied on the binary.
Related errors
- dolt version probe failed
- dolt sql-server exited before listener became ready
- failed to init git in planning repo: %w
- proxy child lost the proxy.lock spawn race for %s: %w
- proxy child exited before becoming ready on explicitly confi
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ba940f8af1ab57c2.
Report an issue: GitHub.