{"record":{"id":"c51f179e3055d086","repo":"gastownhall/beads","slug":"errtransaction","errorCode":"ErrTransaction","errorMessage":"transaction error","messagePattern":"transaction error","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/errors.go","lineNumber":22,"sourceCode":"\t\"database/sql\"\n\t\"errors\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\tmysql \"github.com/go-sql-driver/mysql\"\n\n\t\"github.com/steveyegge/beads/internal/storage\"\n\t\"github.com/steveyegge/beads/internal/storage/dberrors\"\n)\n\n// Sentinel errors for the dolt storage layer.\n// These complement the storage-level sentinels (storage.ErrNotFound, etc.)\n// with dolt-specific error types.\nvar (\n\t// ErrTransaction indicates a transaction begin/commit/rollback failure.\n\tErrTransaction = errors.New(\"transaction error\")\n\n\t// ErrQuery indicates a database query failure.\n\tErrQuery = errors.New(\"query error\")\n\n\t// ErrScan indicates a failure scanning database rows into Go values.\n\tErrScan = errors.New(\"scan error\")\n\n\t// ErrExec indicates a database exec (INSERT/UPDATE/DELETE) failure.\n\tErrExec = errors.New(\"exec error\")\n\n\t// ErrDanglingReference indicates that the pre-push integrity check detected\n\t// missing chunks in the local Dolt noms store. The push was aborted to\n\t// prevent propagating the corruption to the remote. Run bd dolt verify\n\t// to diagnose and recover.\n\tErrDanglingReference = errors.New(\"dangling chunk reference\")\n\n\t// ErrFSCKTimeout indicates that the pre-push integrity check (dolt fsck) did\n\t// not complete within the configured timeout. The push was aborted without","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/errors.go#L4-L40","documentation":"ErrTransaction is the dolt storage layer's sentinel for begin/commit/rollback failures. wrapTransactionError embeds it into the returned error chain (fmt.Errorf with %w), so callers can classify any wrapped failure with errors.Is without string matching.","triggerScenarios":"Any dolt-backed storage operation whose Begin/Commit/Rollback fails — connection drop or timeout during commit, MySQL lock wait timeout (1205) or deadlock (1213) at commit, Dolt merge-conflict autocommit rollback, or a cancelled context killing the transaction mid-flight. The op-specific message and the underlying error are wrapped alongside it.","commonSituations":"Two processes writing concurrently and deadlocking; server restarted mid-transaction; network blip between client and Dolt server; long transaction exceeding lock timeout; merge conflict on commit in multi-branch setups.","solutions":["Check errors.Is(err, dolt.ErrTransaction) to classify, then unwrap (errors.Unwrap / %w chain) for the underlying MySQL error","Retry once on serialization-class causes (deadlock 1213, lock wait timeout 1205) — the transaction was rolled back","Check server health and connectivity (bd doctor) if the cause is a dropped connection","Reduce transaction scope/duration to avoid lock timeouts under concurrency"],"exampleFix":"// before\nif err := store.Update(ctx, issue); err != nil { return err } // opaque failure\n// after\nif err := store.Update(ctx, issue); err != nil {\n    if errors.Is(err, dolt.ErrTransaction) {\n        var mysqlErr *mysql.MySQLError\n        if errors.As(err, &mysqlErr) && (mysqlErr.Number == 1213 || mysqlErr.Number == 1205) {\n            return store.Update(ctx, issue) // safe retry: rolled back\n        }\n    }\n    return err\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isTransactionError(err error) bool {\n    return errors.Is(err, dolt.ErrTransaction)\n}\nfunc isRetryableTxn(err error) bool {\n    var mysqlErr *mysql.MySQLError\n    return errors.As(err, &mysqlErr) && (mysqlErr.Number == 1213 || mysqlErr.Number == 1205)\n}","tryCatchPattern":"if err := op(ctx); err != nil {\n    if errors.Is(err, dolt.ErrTransaction) {\n        if isRetryableTxn(err) {\n            return retry(op, ctx) // rolled back; safe to retry with backoff\n        }\n        return fmt.Errorf(\"transaction failed permanently: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep transactions short to avoid lock timeouts under concurrency","Use bounded retries with backoff on deadlock (1213) / lock-wait-timeout (1205)","Always check errors.Is against the sentinel instead of matching message strings","Monitor server connectivity so dropped connections are detected before writes"],"tags":["go","database","transaction","dolt","sentinel-error"],"backgroundTag":"transaction-commit-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}