gastownhall/beads · error

failed to stage %s: %w

Error message

failed to stage %s: %w

What it means

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.

Source

Thrown at internal/storage/versioncontrolops/mergesettle.go:565

			// Field-level three-way merge, not a table-level --ours/--theirs:
			// a cell only one side changed keeps that side's value and only a
			// genuinely contested cell falls to LWW (automerge.go).
			if err := resolveIssuesFieldMerge(ctx, db, issuesPlan); err != nil {
				return false, err
			}
		case "labels", "comments", "events":
			if err := resolveUnionConflicts(ctx, db, table, unionPlans[table]); err != nil {
				return false, err
			}
		default:
			//nolint:gosec // G201: table is one of the hardcoded constants above.
			if _, err := db.ExecContext(ctx, "CALL DOLT_CONFLICTS_RESOLVE('--theirs', '"+table+"')"); err != nil {
				return false, fmt.Errorf("failed to resolve %s conflicts: %w", table, err)
			}
		}
		//nolint:gosec // G201: table is one of the hardcoded constants above.
		if _, err := db.ExecContext(ctx, "CALL DOLT_ADD('"+table+"')"); err != nil {
			return false, fmt.Errorf("failed to stage %s: %w", table, err)
		}
	}

	return true, nil
}

// CommitResolvedConflicts creates the dolt commit that concludes a merge whose
// conflicts TryAutoResolveMergeConflicts settled. Callers that saw
// resolved=true MUST call this, and only AFTER TryRepairFKCascadeViolations
// has run: DOLT_COMMIT refuses a working set with outstanding constraint
// violations, so a merge carrying both an auto-resolvable conflict and an FK
// cascade violation could never settle while the resolver committed first
// (bd-578h9.14).
func CommitResolvedConflicts(ctx context.Context, db DBConn) error {
	if _, 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 {
		return fmt.Errorf("failed to commit resolved conflicts: %w", err)
	}
	return nil

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped inner error for the concrete Dolt message (unknown table, not in merge, lock timeout).
  2. Confirm the table still exists (SHOW TABLES / dolt_status) and the merge is still active before retrying SettleMerge.
  3. Serialize merge settlement — prevent concurrent bd processes from touching the same working set while conflicts resolve.
  4. Retry once after a transient lock error; if persistent, abort the merge (CALL DOLT_MERGE('--abort')) and re-merge cleanly.

Example fix

// before
if _, err := db.ExecContext(ctx, "CALL DOLT_ADD('"+table+"')"); err != nil {
	return false, fmt.Errorf("failed to stage %s: %w", table, err)
}
// after
if _, err := db.ExecContext(ctx, "CALL DOLT_ADD('"+table+"')"); err != nil {
	// transient lock/engine errors: abort merge so caller can retry from clean state
	_, _ = db.ExecContext(ctx, "CALL DOLT_MERGE('--abort')")
	return false, fmt.Errorf("failed to stage %s (merge aborted, safe to retry): %w", table, err)
}
Defensive patterns

Strategy: retry

Validate before calling

var exists int
err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = ?", table).Scan(&exists)
// also confirm merge still active: SELECT COUNT(*) FROM dolt_conflicts > 0

Type guard

func tableExistsAndConflicted(ctx context.Context, db DBConn, table string) bool {
	var n int
	if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM dolt_conflicts WHERE `table` = ?", table).Scan(&n); err != nil || n == 0 {
		return false
	}
	return true
}

Try / catch

ok, err := TryAutoResolveMergeConflicts(ctx, db)
if err != nil && strings.Contains(err.Error(), "failed to stage") {
	// transient staging failure: abort and retry the whole settle once
	_, _ = db.ExecContext(ctx, "CALL DOLT_MERGE('--abort')")
	// re-run merge + settle here
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/2ecae5498966370e. Report an issue: GitHub.