gastownhall/beads · error

acquire connection for gc: %w

Error message

acquire connection for gc: %w

What it means

DoltGC pins a single pooled connection before delegating to versioncontrolops.DoltGC, because GC depends on session state that pooled connections would lose; this error wraps failure to acquire that connection from the *sql.DB pool. The actual GC has not started — this is purely pool-acquisition failure.

Source

Thrown at internal/storage/dolt/store.go:2877

	if s.localActiveDatabaseDir == "" {
		return 0, &storage.ErrUnsupported{
			Op:      "ActiveDatabaseSize",
			Backend: "dolt-server",
		}
	}
	size, err := storage.MeasureDirectorySize(ctx, s.localActiveDatabaseDir)
	if err != nil {
		return 0, fmt.Errorf("measure active database directory %q: %w", s.localActiveDatabaseDir, err)
	}
	return size, nil
}

// DoltGC runs Dolt garbage collection to reclaim disk space.
// Pins a single connection to avoid session state loss on pooled *sql.DB.
func (s *DoltStore) DoltGC(ctx context.Context) error {
	conn, err := s.db.Conn(ctx)
	if err != nil {
		return fmt.Errorf("acquire connection for gc: %w", err)
	}
	defer conn.Close()
	return versioncontrolops.DoltGC(ctx, conn)
}

// ListRemoteRefs returns the names of all cached remote-tracking refs.
func (s *DoltStore) ListRemoteRefs(ctx context.Context) ([]string, error) {
	return versioncontrolops.ListRemoteRefs(ctx, s.db)
}

// PruneRemoteRefs deletes all cached remote-tracking refs so a post-squash GC
// can reclaim the history they anchor (bd-agctw). Returns the deleted names.
func (s *DoltStore) PruneRemoteRefs(ctx context.Context) ([]string, error) {
	conn, err := s.db.Conn(ctx)
	if err != nil {
		return nil, fmt.Errorf("acquire connection for remote-ref prune: %w", err)
	}
	defer conn.Close()

View on GitHub (pinned to 71377f2769)

Solutions

  1. Retry DoltGC when the pool is less loaded; run GC during quiet periods
  2. Check the wrapped error: context.DeadlineExceeded → raise timeout; dial errors → verify server up and DSN correct
  3. Avoid holding many long transactions concurrently with GC calls
  4. Ensure ctx passed to DoltGC has adequate timeout

Example fix

// before
err := store.DoltGC(ctx) // caller's short ctx
// after
gcCtx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
err := store.DoltGC(gcCtx)
Defensive patterns

Strategy: retry

Validate before calling

// ensure pool is healthy before GC
if err := store.PingContext(ctx); err != nil {
    return fmt.Errorf("skip GC, server unreachable: %w", err)
}

Try / catch

// Go: retry pool acquisition with backoff
var lastErr error
for i := 0; i < 3; i++ {
    if err := store.DoltGC(ctx); err == nil {
        break
    } else if errors.Is(err, context.DeadlineExceeded) {
        lastErr = err
        time.Sleep(time.Duration(1<<i) * time.Second)
        continue
    }
    return err
}

Prevention

When it happens

Trigger: Calling DoltGC(ctx) when db.Conn(ctx) fails: ctx canceled/timed out while waiting for a free connection, pool exhausted by long-running queries, server unreachable so new dial fails, driver ErrBadConn loop.

Common situations: Running GC concurrently with heavy workload saturating the pool; application shutdown canceling ctx; Dolt server restarted; network partition.

Related errors


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