{"record":{"id":"2ecae5498966370e","repo":"gastownhall/beads","slug":"failed-to-stage-s-w","errorCode":null,"errorMessage":"failed to stage %s: %w","messagePattern":"failed to stage (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/mergesettle.go","lineNumber":565,"sourceCode":"\t\t\t// Field-level three-way merge, not a table-level --ours/--theirs:\n\t\t\t// a cell only one side changed keeps that side's value and only a\n\t\t\t// genuinely contested cell falls to LWW (automerge.go).\n\t\t\tif err := resolveIssuesFieldMerge(ctx, db, issuesPlan); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\tcase \"labels\", \"comments\", \"events\":\n\t\t\tif err := resolveUnionConflicts(ctx, db, table, unionPlans[table]); err != nil {\n\t\t\t\treturn false, err\n\t\t\t}\n\t\tdefault:\n\t\t\t//nolint:gosec // G201: table is one of the hardcoded constants above.\n\t\t\tif _, err := db.ExecContext(ctx, \"CALL DOLT_CONFLICTS_RESOLVE('--theirs', '\"+table+\"')\"); err != nil {\n\t\t\t\treturn false, fmt.Errorf(\"failed to resolve %s conflicts: %w\", table, err)\n\t\t\t}\n\t\t}\n\t\t//nolint:gosec // G201: table is one of the hardcoded constants above.\n\t\tif _, err := db.ExecContext(ctx, \"CALL DOLT_ADD('\"+table+\"')\"); err != nil {\n\t\t\treturn false, fmt.Errorf(\"failed to stage %s: %w\", table, err)\n\t\t}\n\t}\n\n\treturn true, nil\n}\n\n// CommitResolvedConflicts creates the dolt commit that concludes a merge whose\n// conflicts TryAutoResolveMergeConflicts settled. Callers that saw\n// resolved=true MUST call this, and only AFTER TryRepairFKCascadeViolations\n// has run: DOLT_COMMIT refuses a working set with outstanding constraint\n// violations, so a merge carrying both an auto-resolvable conflict and an FK\n// cascade violation could never settle while the resolver committed first\n// (bd-578h9.14).\nfunc CommitResolvedConflicts(ctx context.Context, db DBConn) error {\n\tif _, err := db.ExecContext(ctx, \"CALL DOLT_COMMIT('-m', 'auto-resolve merge conflicts: metadata, dependencies, schema_migrations, config, issues (field-level three-way merge), labels/comments/events (union)')\"); err != nil {\n\t\treturn fmt.Errorf(\"failed to commit resolved conflicts: %w\", err)\n\t}\n\treturn nil","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/mergesettle.go#L547-L583","documentation":"This error wraps a failure from CALL DOLT_ADD(table) in TryAutoResolveMergeConflicts, which stages a table after its conflicts were resolved via '--theirs'. Dolt refuses to stage in some states — no such table, no merge in progress, or a storage engine error — and the wrapper adds the table name for diagnosis.","triggerScenarios":"Immediately after successful conflict resolution, CALL DOLT_ADD('<table>') fails: the table was dropped mid-merge, the merge state was cleared by another connection, or the Dolt engine rejects the add (e.g. lock contention or an internal storage error).","commonSituations":"Concurrent writers staging/committing the same working set; a table renamed or dropped between conflict detection and staging; Dolt working-set metadata inconsistency after a crashed process; running against a Dolt version with different DOLT_ADD semantics.","solutions":["Check the wrapped inner error for the concrete Dolt message (unknown table, not in merge, lock timeout).","Confirm the table still exists (SHOW TABLES / dolt_status) and the merge is still active before retrying SettleMerge.","Serialize merge settlement — prevent concurrent bd processes from touching the same working set while conflicts resolve.","Retry once after a transient lock error; if persistent, abort the merge (CALL DOLT_MERGE('--abort')) and re-merge cleanly."],"exampleFix":"// before\nif _, err := db.ExecContext(ctx, \"CALL DOLT_ADD('\"+table+\"')\"); err != nil {\n\treturn false, fmt.Errorf(\"failed to stage %s: %w\", table, err)\n}\n// after\nif _, err := db.ExecContext(ctx, \"CALL DOLT_ADD('\"+table+\"')\"); err != nil {\n\t// transient lock/engine errors: abort merge so caller can retry from clean state\n\t_, _ = db.ExecContext(ctx, \"CALL DOLT_MERGE('--abort')\")\n\treturn false, fmt.Errorf(\"failed to stage %s (merge aborted, safe to retry): %w\", table, err)\n}","handlingStrategy":"retry","validationCode":"var exists int\nerr := db.QueryRowContext(ctx, \"SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?\", table).Scan(&exists)\n// also confirm merge still active: SELECT COUNT(*) FROM dolt_conflicts > 0","typeGuard":"func tableExistsAndConflicted(ctx context.Context, db DBConn, table string) bool {\n\tvar n int\n\tif err := db.QueryRowContext(ctx, \"SELECT COUNT(*) FROM dolt_conflicts WHERE `table` = ?\", table).Scan(&n); err != nil || n == 0 {\n\t\treturn false\n\t}\n\treturn true\n}","tryCatchPattern":"ok, err := TryAutoResolveMergeConflicts(ctx, db)\nif err != nil && strings.Contains(err.Error(), \"failed to stage\") {\n\t// transient staging failure: abort and retry the whole settle once\n\t_, _ = db.ExecContext(ctx, \"CALL DOLT_MERGE('--abort')\")\n\t// re-run merge + settle here\n}","preventionTips":["Do not run concurrent writers on the same working set during merge settlement.","Retry SettleMerge once from a clean state after any staging failure; staging errors are often transient state races.","Verify the table still exists before settling if other code can drop/rename tables.","Keep Dolt and the driver versions aligned with what mergesettle.go expects."],"tags":["dolt","git-like-staging","sql","storage"],"backgroundTag":"dolt-stage-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}