sql.ErrTxDone
GoERRORNotableDatabase

sql: transaction has already been committed or rolled back

Quick Answer

Do not call Rollback after a successful Commit; use a deferred rollback that ignores sql.ErrTxDone.

What this means

Returned when an operation is called on a *sql.Tx after it has already been committed or rolled back. Common with deferred rollback patterns.

Why it happens
  1. 1Rollback called after Commit already succeeded
  2. 2Commit or Rollback called more than once on the same transaction

Fix

Ignore ErrTxDone in deferred rollback

Ignore ErrTxDone in deferred rollback
defer func() {
    if err := tx.Rollback(); err != nil &&
        !errors.Is(err, sql.ErrTxDone) {
        log.Println("rollback:", err)
    }
}()

Why this works

Ignoring ErrTxDone in the deferred rollback is the standard Go transaction pattern.

Code examples
Deferred rollback patterngo
tx, _ := db.Begin()
defer tx.Rollback() // safe to ignore ErrTxDone
// ... do work
tx.Commit()
Detectgo
err := tx.Rollback()
if errors.Is(err, sql.ErrTxDone) {
    fmt.Println("already done")
}
Named return patterngo
func run(db *sql.DB) (err error) {
    tx, _ := db.Begin()
    defer func() {
        if err != nil { tx.Rollback() }
    }()
    return tx.Commit()
}
Sources
Official documentation ↗

Go standard library

Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev

← All Go errors