{"record":{"id":"2abf5547e9132add","repo":"gitbutlerapp/gitbutler","slug":"could-not-find-branch-branch-id-mod","errorCode":null,"errorMessage":"Could not find branch: {branch_id}","messagePattern":"Could not find branch: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/command/legacy/merge/mod.rs","lineNumber":45,"sourceCode":"    // runs here for a friendly message before the prompt; the API enforces it again, along with the\n    // bottom-segment, conflicted-commit, and triangular-remote guards, before mutating anything.\n    let (branch_name, base_branch) = {\n        let mut guard = ctx.exclusive_worktree_access();\n\n        {\n            let (_repo, ws, _db) = ctx.workspace_and_db_with_perm(guard.read_permission())?;\n            if !ws.kind.has_managed_ref() {\n                bail!(\n                    \"`but merge` requires an active GitButler workspace (`gitbutler/workspace`). \\\n                     Switch into the workspace and try again.\"\n                );\n            }\n        }\n\n        let id_map = IdMap::new_from_context(ctx, guard.read_permission())?;\n        let resolved_ids = id_map.parse_using_context(branch_id, ctx)?;\n        if resolved_ids.is_empty() {\n            bail!(\"Could not find branch: {branch_id}\");\n        }\n        if resolved_ids.len() > 1 {\n            bail!(\"Ambiguous branch '{branch_id}', matches multiple items\");\n        }\n\n        let branch_name = match &resolved_ids[0] {\n            CliId::Branch(branch) => branch.name.clone(),\n            other => bail!(\"Expected a branch ID, got {}\", other.kind_for_humans()),\n        };\n\n        let base_branch =\n            but_api::legacy::virtual_branches::get_base_branch_data(ctx, guard.write_permission())?\n                .ok_or_else(|| anyhow::anyhow!(\"No base branch configured\"))?;\n        (branch_name, base_branch)\n    };\n\n    // Display strings for the prompt and the final report. The API recomputes the target/remote\n    // configuration internally; the CLI only needs these names to describe what's about to happen.","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/command/legacy/merge/mod.rs#L27-L63","documentation":"`but merge <branch-id>` resolves its branch argument through the `IdMap` (`id_map.parse_using_context`), which maps user-supplied identifiers (CLI IDs like `br#1`, branch names, or other accepted forms) onto workspace items. When resolution returns an empty list, no branch in the current workspace matches the given identifier, and the command bails with this message naming the original input. Nothing has been mutated at this point.","triggerScenarios":"Calling `but merge <branch_id>` with an identifier that matches zero items in the current workspace: a branch name that does not exist, a stale CLI ID from a previous workspace state, an ID from a different repository, or a typo. The check is `resolved_ids.is_empty()` immediately after `parse_using_context`.","commonSituations":"Branch was renamed or deleted before the merge ran. A script caches a CLI ID (which is positional and changes as the workspace changes) and reuses it after the workspace was reordered. The user types a local branch name that exists in Git but is not applied as a workspace branch. Wrong repo checked out.","solutions":["Run `but branch list` (or `but status`) to see current branches and their exact CLI IDs/names, then use a valid identifier.","Re-resolve the identifier at time of use: prefer stable branch names over positional CLI IDs like `br#2` in scripts.","Create or apply the branch into the workspace if it exists in Git but is not a workspace branch.","Verify you are in the intended repository (the ID map is per-repository/per-workspace)."],"exampleFix":"// before: stale positional id\nbut merge br#2\n// error: Could not find branch: br#2\n// after: resolve current id first\nbut branch list   # shows feature-x as br#1\nbut merge feature-x","handlingStrategy":"validation","validationCode":"// Resolve the identifier against the current workspace before merging:\nconst branches = JSON.parse(runBut(['branch', 'list', '--json']).stdout);\nconst match = branches.find(b => b.name === branchId || b.id === branchId);\nif (!match) {\n  throw new Error(`Branch ${branchId} not in workspace; pick one of: ${branches.map(b => b.id).join(', ')}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  runBut(['merge', branchId]);\n} catch (e) {\n  if (e.stderr.startsWith('Could not find branch:')) {\n    // refresh workspace state and re-resolve the id, then retry once\n    runBut(['branch', 'list']);\n    runBut(['merge', resolvedFreshId]);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Fetch fresh branch IDs (but branch list) immediately before merging; never cache CLI IDs across workspace changes.","Prefer stable branch names over positional IDs like br#2 in scripts.","Ensure the branch is applied in the workspace, not just present as a plain Git ref.","Confirm you are in the intended repository before resolving IDs."],"tags":["cli","gitbutler","branch-resolution","not-found"],"backgroundTag":"entity-not-found","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}