gastownhall/beads · error
merge branch %s: %w
Error message
merge branch %s: %w
What it means
Merge wraps any non-conflict failure of CALL DOLT_MERGE('--author', author, branch) as "merge branch <branch>: <underlying>". This is the fallback branch of Merge's error handling: the merge failed, dolt_conflicts held no readable conflicts, and the error was not the autocommit conflict rejection (so not 4268). Typical wrapped causes are unknown branch, unknown merge ancestor, dirty working set blocking the merge, or invalid author format.
Source
Thrown at internal/storage/versioncontrolops/version_control.go:117
// Dolt reject the implicit transaction (Error 1105: "@autocommit must be
// disabled so that merge conflicts can be resolved ...") before dolt_conflicts
// can even be inspected — conflicts = error here, same as plain `dolt merge`
// with no further flags. Callers that want the flag Dolt's error names —
// resolve-then-commit on conflict — must use MergeWithStrategy instead, which
// runs the merge on a pinned session with the conflict-tolerant flags set
// (#4992).
func Merge(ctx context.Context, db DBConn, branch, author string) ([]storage.Conflict, error) {
_, err := db.ExecContext(ctx, "CALL DOLT_MERGE('--author', ?, ?)", author, branch)
if err != nil {
// Check if the error is due to conflicts.
conflicts, conflictErr := GetConflicts(ctx, db)
if conflictErr == nil && len(conflicts) > 0 {
return conflicts, nil
}
if isMergeConflictAutocommitError(err) {
return nil, fmt.Errorf("merge branch %s: %w (resolve with: bd vc merge %s --strategy ours|theirs)", branch, err, branch)
}
return nil, fmt.Errorf("merge branch %s: %w", branch, err)
}
return nil, nil
}
// isMergeConflictAutocommitError reports whether err is Dolt's autocommit
// rejection of a conflicted merge (Error 1105, "@autocommit must be disabled
// so that merge conflicts can be resolved ..."). It is the shape Merge
// produces for every real conflict, since it runs under autocommit with
// neither dolt_allow_commit_conflicts nor a pinned session (#4992) — matched
// on message because the embedded engine and the MySQL driver report it as
// different error types.
func isMergeConflictAutocommitError(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(err.Error())
return strings.Contains(msg, "merge conflict") && strings.Contains(msg, "autocommit")
}View on GitHub (pinned to 71377f2769)
Solutions
- Check the branch exists: SELECT * FROM dolt_branches (or bd vc branch list) and fix the name.
- Commit or stash pending working-set changes before merging.
- Format author as "Name <email>" and retry the DOLT_MERGE call.
- Read the wrapped error: for 'common ancestor' problems verify the branches share history (fetch first); if it really is a conflict, switch to MergeWithStrategy.
Example fix
// before _, err := versioncontrolops.Merge(ctx, db, "featrue", "bd") // bad branch + malformed author // after _, err := versioncontrolops.Merge(ctx, db, "feature", "Beads Daemon <bd@local>")
Defensive patterns
Strategy: validation
Validate before calling
// verify branch and author shape before merging
var n int
if err := db.QueryRowContext(ctx,
"SELECT COUNT(*) FROM dolt_branches WHERE name = ?", branch).Scan(&n); err != nil || n == 0 {
return fmt.Errorf("branch %q does not exist", branch)
}
if !strings.Contains(author, " <") || !strings.HasSuffix(author, ">") {
return fmt.Errorf("author must be \"Name <email>\", got %q", author)
} Type guard
func validMergeInput(branch, author string) bool {
return branch != "" &&
strings.Contains(author, " <") &&
strings.HasSuffix(author, ">")
} Try / catch
conflicts, err := versioncontrolops.Merge(ctx, db, branch, author)
if err != nil && !isAutocommitConflictErr(err) {
var dbe interface{ Error() string }
if errors.As(err, &dbe) && strings.Contains(dbe.Error(), "unknown branch") {
return fmt.Errorf("fix branch name and retry: %w", err)
}
return fmt.Errorf("merge branch %s failed: %w", branch, err)
} Prevention
- Validate branch names against dolt_branches before merging.
- Always pass author as "Name <email>" — bare usernames make DOLT_MERGE's --author argument fail.
- Commit or clear working-set changes first; Dolt refuses merges over a dirty working set.
- Fetch the remote before merging its branches so shared history exists.
When it happens
Trigger: Calling Merge with a branch that does not exist; merging unrelated histories Dolt refuses; the working set has uncommitted changes Dolt requires committed first; author string not formatted "Name <email>" so DOLT_MERGE rejects the --author argument.
Common situations: Typo'd branch name; merging a branch that was already merged (no-op errors vary); automation passing a bare username instead of "Name <email>"; merge attempted mid-transaction with pending writes.
Related errors
- fast-forward to %s: %w
- merge branch %s: %w
- merge %s: %w
- merge branch %s: %w (resolve with: bd vc merge %s --strategy
- failed to get current branch: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/72a13afa9f5d0783.
Report an issue: GitHub.