gastownhall/beads · error

acquire gc connection: %w

Error message

acquire gc connection: %w

What it means

After opening the GC connection, runShutdownGC grabs a physical connection with db.Conn(ctx). This error means no connection could be acquired before the context deadline or the server refused/failed the connection attempt.

Source

Thrown at internal/storage/dbproxy/server/doltserver.go:399

	if rmErr != nil {
		rmErr = fmt.Errorf("server: DoltServer.Stop: remove pidfile: %w", rmErr)
	}
	return errors.Join(gcErr, waitErr, closeErr, rmErr)
}

func (s *DoltServer) runShutdownGC(ctx context.Context) (retErr error) {
	if s.database == "" || !s.Running(ctx) {
		return nil
	}
	db, err := sql.Open("mysql", s.DSN(ctx, s.database, "root", ""))
	if err != nil {
		return fmt.Errorf("open gc connection: %w", err)
	}
	defer func() { retErr = errors.Join(retErr, db.Close()) }()

	conn, err := db.Conn(ctx)
	if err != nil {
		return fmt.Errorf("acquire gc connection: %w", err)
	}
	defer func() { retErr = errors.Join(retErr, conn.Close()) }()

	if err := versioncontrolops.DoltGC(ctx, conn); err != nil {
		retErr = errors.Join(retErr, err)
	}
	if _, err := conn.ExecContext(ctx, "CALL DOLT_STATS_GC()"); err != nil {
		retErr = errors.Join(retErr, fmt.Errorf("dolt_stats_gc: %w", err))
	}
	return retErr
}

func (s *DoltServer) Running(_ context.Context) bool {
	if s.egCtx == nil {
		return false
	}
	return s.egCtx.Err() == nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Increase the Stop/stopWithTimeout timeout so the context is not cancelled during GC
  2. Check server logs for 'too many connections' or refusal at shutdown; ensure Stop runs before the underlying server process is killed
  3. Verify no other caller holds all connections; close leaked connections elsewhere in the app
  4. Retry once after a short delay if the error is context-deadline related and the server is still Running

Example fix

// before
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
err := server.Stop(ctx)
// after
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // allow GC to connect
defer cancel()
err := server.Stop(ctx)
Defensive patterns

Strategy: retry

Validate before calling

// before Stop, confirm server still accepting connections
if !server.Running(ctx) {
    return nil // nothing to GC
}

Try / catch

err := server.Stop(ctx)
if err != nil && strings.Contains(err.Error(), "acquire gc connection") {
    // give the server a moment, retry once with fresh context
    retryCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()
    err = server.Stop(retryCtx)
}

Prevention

When it happens

Trigger: DoltServer.Stop during shutdown GC when the server has already stopped accepting connections (race between Stop and server teardown), the context is cancelled/timed out (stopWithTimeout deadline), or max connections are exhausted.

Common situations: Shutdown timeout too short so ctx is done before db.Conn completes; Stop called twice concurrently so the second run races the dying server; external load maxing out Dolt's connection limit.

Related errors


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