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

  1. Check that rootDir exists, is a directory, and is writable by the current user (ls -ld <rootDir>; touch <rootDir>/.wtest).
  2. Free disk space or raise the quota if the filesystem is full (df -h <rootDir>).
  3. Remove any stray non-regular file named proxy.pid in rootDir and retry the start.
  4. Fix mount permissions (chmod/chown, remount rw) or point bd at a writable rootDir.
  5. 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

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


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/7ba35e5e24670f56. Report an issue: GitHub.