Ctrl-C during a backup can end with "FATAL: failed to rollback transaction" and exit 1 instead of the interrupted exit #301

Open
opened 2026-10-13 00:47:09 +02:00 by clawbot · 1 comment
Collaborator

Found by the defect hunt in #288 (part 2).

What is wrong: transactions are bound to the run's context. On cancel, database/sql rolls the transaction back itself, so the explicit Rollback returns sql.ErrTxDone; WithTx (internal/database/repositories.go) treats any rollback error as fatal and calls os.Exit(1). The user gets a message that suggests damage to the local index, exit 1 instead of 130 ("interrupted before the command finished"), and deferred cleanup is skipped.

How it was shown: 8000 empty files, one backup, then 6 runs each sent SIGINT as soon as "Associating ... unchanged files" printed: all 6 exited 1 with FATAL: failed to rollback transaction: sql: transaction has already been committed or rolled back.

Definition of done

  • A rollback that finds the transaction already rolled back (sql.ErrTxDone) is not an error: WithTx returns the body's error, and an interrupted backup ends with the documented interrupted exit and message.
  • No path in WithTx exits the process; a real rollback failure is returned as an error.
  • A test covers a transaction whose context is cancelled during the body.

Model: opus-5-5

Found by the defect hunt in https://git.eeqj.de/sneak/vaultik/issues/288 (part 2). **What is wrong:** transactions are bound to the run's context. On cancel, `database/sql` rolls the transaction back itself, so the explicit `Rollback` returns `sql.ErrTxDone`; `WithTx` (`internal/database/repositories.go`) treats any rollback error as fatal and calls `os.Exit(1)`. The user gets a message that suggests damage to the local index, exit 1 instead of 130 ("interrupted before the command finished"), and deferred cleanup is skipped. **How it was shown:** 8000 empty files, one backup, then 6 runs each sent SIGINT as soon as "Associating ... unchanged files" printed: all 6 exited 1 with `FATAL: failed to rollback transaction: sql: transaction has already been committed or rolled back`. **Definition of done** - A rollback that finds the transaction already rolled back (`sql.ErrTxDone`) is not an error: `WithTx` returns the body's error, and an interrupted backup ends with the documented interrupted exit and message. - No path in `WithTx` exits the process; a real rollback failure is returned as an error. - A test covers a transaction whose context is cancelled during the body. Model: opus-5-5
clawbot self-assigned this 2026-10-13 00:47:09 +02:00
Author
Collaborator

Implemented in #343: WithTx no longer treats the rollback that database/sql has already done after a cancel as a failure, and no longer ends the process on a rollback error, so an interrupted backup ends with the interrupted exit and message.

Model: opus-5-5

Implemented in https://git.eeqj.de/sneak/vaultik/pulls/343: `WithTx` no longer treats the rollback that `database/sql` has already done after a cancel as a failure, and no longer ends the process on a rollback error, so an interrupted backup ends with the interrupted exit and message. Model: opus-5-5
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/vaultik#301