{"record":{"id":"d5b55e26d02770a3","repo":"gastownhall/beads","slug":"acquire-gc-connection-w","errorCode":null,"errorMessage":"acquire gc connection: %w","messagePattern":"acquire gc connection: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/server/doltserver.go","lineNumber":399,"sourceCode":"\tif rmErr != nil {\n\t\trmErr = fmt.Errorf(\"server: DoltServer.Stop: remove pidfile: %w\", rmErr)\n\t}\n\treturn errors.Join(gcErr, waitErr, closeErr, rmErr)\n}\n\nfunc (s *DoltServer) runShutdownGC(ctx context.Context) (retErr error) {\n\tif s.database == \"\" || !s.Running(ctx) {\n\t\treturn nil\n\t}\n\tdb, err := sql.Open(\"mysql\", s.DSN(ctx, s.database, \"root\", \"\"))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"open gc connection: %w\", err)\n\t}\n\tdefer func() { retErr = errors.Join(retErr, db.Close()) }()\n\n\tconn, err := db.Conn(ctx)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"acquire gc connection: %w\", err)\n\t}\n\tdefer func() { retErr = errors.Join(retErr, conn.Close()) }()\n\n\tif err := versioncontrolops.DoltGC(ctx, conn); err != nil {\n\t\tretErr = errors.Join(retErr, err)\n\t}\n\tif _, err := conn.ExecContext(ctx, \"CALL DOLT_STATS_GC()\"); err != nil {\n\t\tretErr = errors.Join(retErr, fmt.Errorf(\"dolt_stats_gc: %w\", err))\n\t}\n\treturn retErr\n}\n\nfunc (s *DoltServer) Running(_ context.Context) bool {\n\tif s.egCtx == nil {\n\t\treturn false\n\t}\n\treturn s.egCtx.Err() == nil\n}","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/server/doltserver.go#L381-L417","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Increase the Stop/stopWithTimeout timeout so the context is not cancelled during GC","Check server logs for 'too many connections' or refusal at shutdown; ensure Stop runs before the underlying server process is killed","Verify no other caller holds all connections; close leaked connections elsewhere in the app","Retry once after a short delay if the error is context-deadline related and the server is still Running"],"exampleFix":"// before\nctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\ndefer cancel()\nerr := server.Stop(ctx)\n// after\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // allow GC to connect\ndefer cancel()\nerr := server.Stop(ctx)","handlingStrategy":"retry","validationCode":"// before Stop, confirm server still accepting connections\nif !server.Running(ctx) {\n    return nil // nothing to GC\n}","typeGuard":null,"tryCatchPattern":"err := server.Stop(ctx)\nif err != nil && strings.Contains(err.Error(), \"acquire gc connection\") {\n    // give the server a moment, retry once with fresh context\n    retryCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\n    defer cancel()\n    err = server.Stop(retryCtx)\n}","preventionTips":["Use a shutdown timeout large enough for GC (tens of seconds, not 1-2s)","Avoid calling Stop concurrently from multiple goroutines","Monitor connection-pool usage so external load can't starve the GC connection"],"tags":["go","mysql","connection","timeout","shutdown"],"backgroundTag":"connection-acquisition-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}