{"record":{"id":"bb041fe759e9da1c","repo":"gastownhall/beads","slug":"failed-to-begin-transaction-w-bb041f","errorCode":null,"errorMessage":"failed to begin transaction: %w","messagePattern":"failed to begin transaction: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/wisps.go","lineNumber":191,"sourceCode":"\n\tvar labels []string\n\tfor rows.Next() {\n\t\tvar label string\n\t\tif err := rows.Scan(&label); err != nil {\n\t\t\treturn nil, wrapScanError(\"scan wisp label\", err)\n\t\t}\n\t\tlabels = append(labels, label)\n\t}\n\treturn labels, rows.Err()\n}\n\n// updateWisp updates fields on a wisp in the wisps table.\n// Delegates SQL work to issueops.UpdateIssueInTx; no Dolt versioning needed\n// since wisps live in dolt_ignored tables.\nfunc (s *DoltStore) updateWisp(ctx context.Context, id string, updates map[string]interface{}, actor string) error {\n\ttx, err := s.db.BeginTx(ctx, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to begin transaction: %w\", err)\n\t}\n\tdefer func() { _ = tx.Rollback() }()\n\n\tclearJournalScope := s.scopeEventsJournalTransaction(tx)\n\tdefer clearJournalScope()\n\n\tif _, err := issueops.UpdateIssueInTx(ctx, tx, id, updates, actor); err != nil {\n\t\treturn err\n\t}\n\n\treturn s.commitSQLTx(ctx, \"commit update wisp\", tx)\n}\n\n// updateWispChecked updates a wisp with the optional atomic preconditions of\n// UpdateIssueChecked, mirroring updateWisp but first enforcing — in the SAME\n// transaction — opts.ExpectedVersion (issueops.CheckVersionInTx →\n// storage.ErrVersionMismatch) and the opts.ExpectedAssignee/ExpectedStatus\n// field guards (issueops.CheckExpectedFieldsInTx → ErrAssigneeMismatch/","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/wisps.go#L173-L209","documentation":"updateWisp could not start a database transaction via s.db.BeginTx; the driver's error is wrapped as 'failed to begin transaction'. Nothing was modified — the failure happens before any wisp update SQL runs. This points to database connectivity/availability rather than the update itself.","triggerScenarios":"Called from updateIssue for an ephemeral wisp when the underlying Dolt/SQL connection pool is exhausted, the database is closed/locked, or the context is already canceled at BeginTx time.","commonSituations":"Database file locked by another process or server unavailable; connection pool saturated under high concurrency; ctx canceled/expired before the update; Dolt server restarting during deploys.","solutions":["Check database connectivity and that the Dolt server/db file is reachable and not locked","Retry the update — begin failures are often transient","Inspect the wrapped cause (%w) for driver-specific diagnostics (pool timeout, locked DB, canceled context)","Reduce concurrency or raise connection-pool limits if pool exhaustion recurs"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"ctx, cancel := context.WithTimeout(ctx, 30*time.Second)\ndefer cancel()\nif err := db.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"database unreachable before update: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := store.UpdateIssue(ctx, id, updates)\nif err != nil && strings.Contains(err.Error(), \"failed to begin transaction\") {\n    return retryWithBackoff(3, 500*time.Millisecond, func() error {\n        return store.UpdateIssue(ctx, id, updates)\n    })\n}","preventionTips":["Ping the database or check connectivity before write batches","Use contexts with realistic deadlines; avoid pre-canceled contexts","Watch for DB file locks / Dolt server availability during deploys","Cap concurrency so the connection pool is not exhausted"],"tags":["database","transaction","connectivity","go"],"backgroundTag":"transaction-begin-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}