{"record":{"id":"ebcfb881353471f0","repo":"jackc/pgx","slug":"commit-unexpectedly-resulted-in-rollback","errorCode":null,"errorMessage":"commit unexpectedly resulted in rollback","messagePattern":"commit unexpectedly resulted in rollback","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tx.go","lineNumber":90,"sourceCode":"\t}\n\tif txOptions.AccessMode != \"\" {\n\t\tbuf.WriteByte(' ')\n\t\tbuf.WriteString(string(txOptions.AccessMode))\n\t}\n\tif txOptions.DeferrableMode != \"\" {\n\t\tbuf.WriteByte(' ')\n\t\tbuf.WriteString(string(txOptions.DeferrableMode))\n\t}\n\n\treturn buf.String()\n}\n\nvar ErrTxClosed = errors.New(\"tx is closed\")\n\n// ErrTxCommitRollback occurs when an error has occurred in a transaction and\n// Commit() is called. PostgreSQL accepts COMMIT on aborted transactions, but\n// it is treated as ROLLBACK.\nvar ErrTxCommitRollback = errors.New(\"commit unexpectedly resulted in rollback\")\n\n// Begin starts a transaction. Unlike [database/sql], the context only affects the begin command. i.e. there is no\n// auto-rollback on context cancellation.\nfunc (c *Conn) Begin(ctx context.Context) (Tx, error) {\n\treturn c.BeginTx(ctx, TxOptions{})\n}\n\n// BeginTx starts a transaction with txOptions determining the transaction mode. Unlike [database/sql], the context only\n// affects the begin command. i.e. there is no auto-rollback on context cancellation.\nfunc (c *Conn) BeginTx(ctx context.Context, txOptions TxOptions) (Tx, error) {\n\t_, err := c.Exec(ctx, txOptions.beginSQL())\n\tif err != nil {\n\t\t// begin kills the connection upon receiving fatal, panic or non PGError errors,\n\t\t// but does not otherwise as the connection should be reusable.\n\t\tvar pgErr *pgconn.PgError\n\t\tif !errors.As(err, &pgErr) || isConnectionFatal(pgErr) {\n\t\t\tc.die()\n\t\t}","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/tx.go#L72-L108","documentation":"Sentinel ErrTxCommitRollback: Commit() was called on a transaction whose prior statement had already failed, so PostgreSQL treated the COMMIT as a ROLLBACK — the transaction's effects were not persisted. The earlier in-transaction error is the root cause; this error just reports how the abort concluded.","triggerScenarios":"Thrown at tx.go:90 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Inspect and fix the earlier error that aborted the transaction","Decide idempotency: safe to retry the whole transaction if needed","Check errors.Is(err, pgx.ErrTxCommitRollback) to detect aborted commits specifically"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}