{"record":{"id":"72a13afa9f5d0783","repo":"gastownhall/beads","slug":"merge-branch-s-w-72a13a","errorCode":null,"errorMessage":"merge branch %s: %w","messagePattern":"merge branch (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/version_control.go","lineNumber":117,"sourceCode":"// Dolt reject the implicit transaction (Error 1105: \"@autocommit must be\n// disabled so that merge conflicts can be resolved ...\") before dolt_conflicts\n// can even be inspected — conflicts = error here, same as plain `dolt merge`\n// with no further flags. Callers that want the flag Dolt's error names —\n// resolve-then-commit on conflict — must use MergeWithStrategy instead, which\n// runs the merge on a pinned session with the conflict-tolerant flags set\n// (#4992).\nfunc Merge(ctx context.Context, db DBConn, branch, author string) ([]storage.Conflict, error) {\n\t_, err := db.ExecContext(ctx, \"CALL DOLT_MERGE('--author', ?, ?)\", author, branch)\n\tif err != nil {\n\t\t// Check if the error is due to conflicts.\n\t\tconflicts, conflictErr := GetConflicts(ctx, db)\n\t\tif conflictErr == nil && len(conflicts) > 0 {\n\t\t\treturn conflicts, nil\n\t\t}\n\t\tif isMergeConflictAutocommitError(err) {\n\t\t\treturn nil, fmt.Errorf(\"merge branch %s: %w (resolve with: bd vc merge %s --strategy ours|theirs)\", branch, err, branch)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"merge branch %s: %w\", branch, err)\n\t}\n\treturn nil, nil\n}\n\n// isMergeConflictAutocommitError reports whether err is Dolt's autocommit\n// rejection of a conflicted merge (Error 1105, \"@autocommit must be disabled\n// so that merge conflicts can be resolved ...\"). It is the shape Merge\n// produces for every real conflict, since it runs under autocommit with\n// neither dolt_allow_commit_conflicts nor a pinned session (#4992) — matched\n// on message because the embedded engine and the MySQL driver report it as\n// different error types.\nfunc isMergeConflictAutocommitError(err error) bool {\n\tif err == nil {\n\t\treturn false\n\t}\n\tmsg := strings.ToLower(err.Error())\n\treturn strings.Contains(msg, \"merge conflict\") && strings.Contains(msg, \"autocommit\")\n}","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/version_control.go#L99-L135","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n_, err := versioncontrolops.Merge(ctx, db, \"featrue\", \"bd\") // bad branch + malformed author\n// after\n_, err := versioncontrolops.Merge(ctx, db, \"feature\", \"Beads Daemon <bd@local>\")","handlingStrategy":"validation","validationCode":"// verify branch and author shape before merging\nvar n int\nif err := db.QueryRowContext(ctx,\n    \"SELECT COUNT(*) FROM dolt_branches WHERE name = ?\", branch).Scan(&n); err != nil || n == 0 {\n    return fmt.Errorf(\"branch %q does not exist\", branch)\n}\nif !strings.Contains(author, \" <\") || !strings.HasSuffix(author, \">\") {\n    return fmt.Errorf(\"author must be \\\"Name <email>\\\", got %q\", author)\n}","typeGuard":"func validMergeInput(branch, author string) bool {\n    return branch != \"\" &&\n        strings.Contains(author, \" <\") &&\n        strings.HasSuffix(author, \">\")\n}","tryCatchPattern":"conflicts, err := versioncontrolops.Merge(ctx, db, branch, author)\nif err != nil && !isAutocommitConflictErr(err) {\n    var dbe interface{ Error() string }\n    if errors.As(err, &dbe) && strings.Contains(dbe.Error(), \"unknown branch\") {\n        return fmt.Errorf(\"fix branch name and retry: %w\", err)\n    }\n    return fmt.Errorf(\"merge branch %s failed: %w\", branch, err)\n}","preventionTips":["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."],"tags":["git","dolt","merge","branch"],"backgroundTag":"merge-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}