{"record":{"id":"87ce70b16fe355aa","repo":"gastownhall/beads","slug":"check-pending-changes-before-commit-w","errorCode":null,"errorMessage":"check pending changes before commit: %w","messagePattern":"check pending changes before commit: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/commit.go","lineNumber":68,"sourceCode":"\t}\n\n\t// dirtyTables tracks tables touched by a write statement, but a statement\n\t// can succeed without changing any rows (e.g. an idempotent\n\t// \"INSERT ... ON DUPLICATE KEY UPDATE value = VALUES(value)\" re-writing the\n\t// same value, an INSERT IGNORE that hit a duplicate, or an UPDATE whose WHERE\n\t// matched nothing). Staging + committing in that case is a no-op that Dolt\n\t// rejects with a \"nothing to commit\" warning logged server-side on every call\n\t// — at high-frequency callers (config/metadata heartbeats, reconcile counters,\n\t// idempotent label/dependency writes) this floods the Dolt log.\n\t//\n\t// Cheap fast-path: if NOTHING is pending in the whole working set (excluding\n\t// dolt-ignored tables, which cannot be staged), skip without touching Dolt's\n\t// staging machinery. Note: callers like Update/Close also write an events row,\n\t// so a zero-rows main-table write can still be a real change — dolt_status\n\t// captures that correctly where a rows-affected check would not.\n\tpending, err := issueops.HasPendingChanges(ctx, conn)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"check pending changes before commit: %w\", err)\n\t}\n\tif !pending {\n\t\treturn nil\n\t}\n\n\tfor table := range dirtyTables {\n\t\tif _, err := conn.ExecContext(ctx, \"CALL DOLT_ADD(?)\", table); err != nil {\n\t\t\treturn fmt.Errorf(\"dolt add %s: %w\", table, err)\n\t\t}\n\t}\n\n\t// Precise guard: HasPendingChanges above is global, but we only DOLT_ADD the\n\t// dirty-tracked tables. When those specific tables turn out clean (idempotent\n\t// no-op) while some UNRELATED table is concurrently dirty, the fast-path does\n\t// not fire yet staging stages nothing — so DOLT_COMMIT('-m') would still emit\n\t// the \"nothing to commit\" warning. Check the STAGED set (exactly what '-m'\n\t// will commit) and skip the empty commit.\n\tstaged, err := issueops.HasStagedChanges(ctx, conn)","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/commit.go#L50-L86","documentation":"StageAndCommit first calls issueops.HasPendingChanges to decide whether anything is worth committing; failures there are wrapped as 'check pending changes before commit: %w'. This is a pre-flight dolt_status query, so the error usually reflects a connection or query problem, not a commit problem. The commit is intentionally skipped when nothing is pending.","triggerScenarios":"Calling StageAndCommit when the HasPendingChanges query (dolt_status scan) fails — dead connection, Dolt server unavailable, or schema/version change affecting dolt_status output.","commonSituations":"Server restarted between writes and commit; connection pool returned a broken session; embedded Dolt process crashed; querying dolt_status on a database where that procedure is unavailable.","solutions":["Inspect the wrapped driver error and reconnect/reopen the Dolt connection if it's a connection failure","Retry StageAndCommit after connectivity is restored — it is safe to re-run","Verify dolt_status works on the target Dolt version","Check whether a transaction/lock conflict is blocking the dolt_status read and release the conflicting session"],"exampleFix":"// before\nerr := versioncontrolops.StageAndCommit(ctx, db, tables, msg, author)\n// after\nif err := db.PingContext(ctx); err != nil {\n    db = reconnect(ctx)\n}\nerr := versioncontrolops.StageAndCommit(ctx, db, tables, msg, author)","handlingStrategy":"retry","validationCode":"if err := conn.PingContext(ctx); err != nil {\n    return fmt.Errorf(\"connection unhealthy before commit: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := versioncontrolops.StageAndCommit(ctx, conn, tables, msg, author)\nif err != nil && strings.Contains(err.Error(), \"check pending changes before commit\") {\n    conn = reconnect(ctx)\n    err = versioncontrolops.StageAndCommit(ctx, conn, tables, msg, author)\n}","preventionTips":["Ping or health-check the connection before committing","Retry StageAndCommit on transient failures — it's idempotent","Keep Dolt versions current so dolt_status queries behave as expected","Avoid holding conflicting transactions/locks across commit calls"],"tags":["dolt","sql","commit","staging"],"backgroundTag":"dolt-status-check-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}