gastownhall/beads · error
write pid file: %w
Error message
write pid file: %w
What it means
ListenAndServe fails during final startup publishing when pidfile.Write cannot persist proxy.pid (the record pointing clients at the proxy's data port, control port, and identity). Before returning, the proxy rolls back: the backend is stopped and the backend-stop stat is incremented, so the start aborts cleanly rather than publishing a half-started proxy. This is a filesystem error wrapped with a stable 'write pid file' prefix.
Source
Thrown at internal/storage/dbproxy/proxy/server.go:328
_ = stopBackendBounded(p.server)
return fmt.Errorf("re-check proxy stop epoch before publish: %w", err)
} else if changed {
return abortInterruptedStart()
}
if err := pidfile.Write(p.rootDir, PIDFileName, pidfile.PidFile{
Pid: os.Getpid(),
Port: dataPort.Port,
UpstreamID: upstreamID,
Schema: pidfile.SchemaV2,
Kind: pidfile.KindProxy,
Birth: string(birth),
RootID: rootID,
ControlPort: control.Port(),
}); err != nil {
p.stats.IncBackendStop()
_ = stopBackendBounded(p.server)
return fmt.Errorf("write pid file: %w", err)
}
defer func() { _ = pidfile.Remove(p.rootDir, PIDFileName) }()
g, gctx := errgroup.WithContext(ctx)
g.Go(func() error {
<-gctx.Done()
_ = p.listener.Close()
_ = control.Close()
return nil
})
g.Go(func() error { return p.idleWatcher(gctx) })
g.Go(func() error { return p.acceptLoop(gctx) })
runErr := g.Wait()
_ = p.conns.Wait()
p.stats.IncBackendStop()
stopErr := stopBackendBounded(p.server)
if stopErr != nil {View on GitHub (pinned to 71377f2769)
Solutions
- Check that rootDir exists, is a directory, and is writable by the current user (ls -ld <rootDir>; touch <rootDir>/.wtest).
- Free disk space or raise the quota if the filesystem is full (df -h <rootDir>).
- Remove any stray non-regular file named proxy.pid in rootDir and retry the start.
- Fix mount permissions (chmod/chown, remount rw) or point bd at a writable rootDir.
- Retry the start; if persistent, inspect the wrapped cause after 'write pid file: ' for the exact syscall error.
Example fix
// before (shell): start on a read-only checkout bd dolt start # write pid file: open /repo/.beads/proxy.pid: read-only file system // after mount -o remount,rw /repo # or run bd from a writable workspace bd dolt start
Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(rootDir)
if err != nil || !info.IsDir() {
return fmt.Errorf("rootDir %s missing or not a directory", rootDir)
}
if f, err := os.CreateTemp(rootDir, ".wtest*"); err != nil {
return fmt.Errorf("rootDir %s not writable: %w", rootDir, err)
} else {
f.Close(); os.Remove(f.Name())
} Try / catch
if err := proxy.ListenAndServe(ctx, ...); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && strings.Contains(err.Error(), "write pid file") {
// rollback already done by the proxy; surface rootDir permission/space issue
}
return err
} Prevention
- Ensure the bd workspace rootDir is writable by the service user before starting
- Monitor free disk space where workspaces live
- Do not run starts on read-only mounts; keep control files on a writable volume
- Clean stray proxy.pid directories/files before start
When it happens
Trigger: Calling the proxy start (ListenAndServe) when writing <rootDir>/proxy.pid fails: unwritable or read-only rootDir, disk full, rootDir deleted mid-start, path is a directory or has wrong permissions, or an immutable/ACL-blocked file at that path.
Common situations: Running bd under a user without write access to the workspace; a full tmpfs/quotad disk on CI; NFS/EACCES issues; a stale directory sitting where proxy.pid belongs; container with a read-only mount of the repo root.
Related errors
- writing PID file: %w
- read backend record %s: %w
- quarantine dead unverifiable backend record: %w
- quarantine orphan backend record: %w
- proxy.ForceStopUnverified: re-read %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7ba35e5e24670f56.
Report an issue: GitHub.