gastownhall/beads · error
server: DoltServer.Start: acquire %s: %w
Error message
server: DoltServer.Start: acquire %s: %w
What it means
DoltServer.Start could not create the advisory file lock proxy-child.lock in the server's root directory. This library uses the lock to guarantee only one managed dolt sql-server process exists per root dir; TryLock fails when the lock file exists and is held by another process, or the file cannot be created/opened.
Source
Thrown at internal/storage/dbproxy/server/doltserver.go:225
return nil
}
if !isRetryableDoltInitErr(err) {
return backoff.Permanent(err)
}
return err
}
return backoff.Retry(op, backoff.WithMaxRetries(backoff.WithContext(bo, ctx), maxRetries))
}
func (s *DoltServer) Start(ctx context.Context) error {
if s.eg != nil || s.egCtx != nil {
return fmt.Errorf("server: DoltServer.Start: server already started")
}
lock, err := util.TryLock(filepath.Join(s.rootDir, LockFileName))
if err != nil {
return fmt.Errorf("server: DoltServer.Start: acquire %s: %w", LockFileName, err)
}
if err := s.doltConfigure(ctx); err != nil {
lock.Unlock()
return err
}
if err := s.doltInitWithRetries(ctx); err != nil {
lock.Unlock()
return err
}
args := []string{
"sql-server",
"--config", s.configPath,
}
managedCtx, cancel := context.WithCancel(context.Background())View on GitHub (pinned to 71377f2769)
Solutions
- Check for another live process using the same rootDir (ps / pgrep for `dolt sql-server`) and stop it, or use a different rootDir.
- Verify no stale holder: if no dolt process is running but the lock is reported held, remove the leftover proxy-child.lock and retry.
- Check permissions on rootDir; ensure the current user can create and lock files there.
- Ensure Start() is not called concurrently for the same rootDir within your application; serialize or use a single server instance.
Example fix
// before
srv.Start(ctx) // may fail: proxy-child.lock held
// after
if !srv.Running(ctx) {
if err := srv.Start(ctx); err != nil {
log.Fatalf("start server: %v (is another bd instance using this dir?)", err)
}
} Defensive patterns
Strategy: validation
Validate before calling
// Before Start: check the lock is not held by a live process.
lockPath := filepath.Join(rootDir, "proxy-child.lock")
if lock, err := util.TryLock(lockPath); err != nil {
return fmt.Errorf("storage dir %s appears to be in use by another process: %w", rootDir, err)
} else {
lock.Unlock() // release; Start will re-acquire
} Try / catch
if err := srv.Start(ctx); err != nil {
if strings.Contains(err.Error(), "acquire proxy-child.lock") {
// another instance owns this data dir; abort or point at another rootDir
return fmt.Errorf("data dir busy: %w", err)
}
return err
} Prevention
- One process per data directory — enforce in your deployment (supervisors, k8s single-writer).
- Check for running `dolt sql-server` processes before starting.
- After crashes, verify no stale lock holder before restarting.
- Ensure the user running the app owns rootDir.
When it happens
Trigger: Calling Start() when another DoltServer (or a previous uncleanly-terminated process) still holds proxy-child.lock in rootDir; concurrent Start() calls on servers sharing rootDir; rootDir not writable so the lock file cannot be created.
Common situations: Two beads instances pointed at the same storage dir; a crashed run left a stale lock owner entry; running the app as a different user without write access to the data directory; read-only filesystem or container volume.
Related errors
- creating beads directory: %w
- opening lock file: %w
- util: creating lock directory: %w
- util: opening lock file: %w
- workspacegate: open gate %s: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/b6583a64971e0d5b.
Report an issue: GitHub.