When a query fails because the context has been canceled, pq will
return "driver: bad connection" from tx.Rollback. Do not panic in
this case. See https://github.com/lib/pq/issues/1137

Taken from this sourcehut patch submission:

https://lists.sr.ht/~sircmpwn/sr.ht-dev/patches/43630
1 files changed, 17 insertions(+), 9 deletions(-)

M database/sql.go
M database/sql.go +17 -9
@@ 3,6 3,7 @@ package database
 import (
 	"context"
 	"database/sql"
+	sqldriver "database/sql/driver"
 	"errors"
 	"time"
 

          
@@ 18,7 19,7 @@ type contextKey struct {
 }
 
 // TxOptionsRO read only transaction rules
-var TxOptionsRO *sql.TxOptions = &sql.TxOptions{Isolation: 0, ReadOnly: true}
+var TxOptionsRO = &sql.TxOptions{Isolation: 0, ReadOnly: true}
 
 // ContextWithTimeout returns a context with query timeout
 func ContextWithTimeout(

          
@@ 49,17 50,24 @@ func WithTx(ctx context.Context, opts *s
 	}
 	defer tx.Rollback()
 	err = fn(tx)
+
+	var txErr error
 	if err != nil {
-		err := tx.Rollback()
-		if err != nil && err != sql.ErrTxDone {
-			panic(err)
-		}
+		txErr = tx.Rollback()
 	} else {
-		err := tx.Commit()
-		if err != nil && err != sql.ErrTxDone {
-			panic(err)
-		}
+		txErr = tx.Commit()
 	}
+
+	if errors.Is(err, context.Canceled) && errors.Is(txErr, sqldriver.ErrBadConn) {
+		// When a query fails because the context has been canceled, pq will
+		// return "driver: bad connection" from tx.Rollback. Do not panic in
+		// this case. See https://github.com/lib/pq/issues/1137
+		return err
+	}
+	if txErr != nil && txErr != sql.ErrTxDone {
+		panic(err)
+	}
+
 	return err
 }