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

  1. Check for another live process using the same rootDir (ps / pgrep for `dolt sql-server`) and stop it, or use a different rootDir.
  2. Verify no stale holder: if no dolt process is running but the lock is reported held, remove the leftover proxy-child.lock and retry.
  3. Check permissions on rootDir; ensure the current user can create and lock files there.
  4. 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

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


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