gitbutlerapp/gitbutler · error
No base branch configured
Error message
No base branch configured
What it means
`but land` resolves the requested branch id, then asks `but_api::legacy::virtual_branches::get_base_branch_data` for the workspace's base (target) branch. A `None` return — no target branch configured in this workspace — is turned into this error, because landing needs a target to land onto.
Source
Thrown at crates/but/src/command/legacy/land/mod.rs:58
}
let id_map = IdMap::new_from_context(ctx, guard.read_permission())?;
let resolved_ids = id_map.parse_using_context(branch_id, ctx)?;
if resolved_ids.is_empty() {
bail!("Could not find branch: {branch_id}");
}
if resolved_ids.len() > 1 {
bail!("Ambiguous branch '{branch_id}', matches multiple items");
}
let branch_name = match &resolved_ids[0] {
CliId::Branch(branch) => branch.name.clone(),
other => bail!("Expected a branch ID, got {}", other.kind_for_humans()),
};
let base_branch =
but_api::legacy::virtual_branches::get_base_branch_data(ctx, guard.write_permission())?
.ok_or_else(|| anyhow::anyhow!("No base branch configured"))?;
(branch_name, base_branch)
};
// Display strings for the prompt and the final report. The API recomputes the target/remote
// configuration internally; the CLI only needs these names to describe what's about to happen.
let target_branch_name = base_branch.short_name.clone();
let push_remote_name = if base_branch.push_remote_name.is_empty() {
base_branch.remote_name.clone()
} else {
base_branch.push_remote_name.clone()
};
let target_display = format!("{push_remote_name}/{target_branch_name}");
// With --whole-stack the confirmation must disclose everything that will be published, not
// just the branch the user typed — including commits on segments that no longer have a name.
// The API re-derives and enforces this; what's gathered here is display.
let lower = if whole_stack {
but_api::land::lower_stack(ctx, &branch_name)?View on GitHub (pinned to caf1f223d3)
Solutions
- Set the target branch: `but config target <branch>` (e.g. `but config target origin/main`)
- Make sure the remote branch exists locally first: `git fetch <remote>`
- Verify with `but config target` that a base branch is now reported
- Re-run `but land <branch>`
Example fix
# before but land my-branch # error: No base branch configured # after but config target origin/main but land my-branch
Defensive patterns
Strategy: validation
Validate before calling
# Preflight: a configured target is required before landing git fetch origin but config target origin/main # idempotent setup if unset but land my-branch
Try / catch
// Surface setup guidance when land fails on missing target
let out = Command::new("but").args(["land", branch]).output()?;
if !out.status.success()
&& String::from_utf8_lossy(&out.stderr).contains("No base branch configured")
{
eprintln!("run `but config target <remote/branch>` first");
} Prevention
- Run the onboarding/setup flow right after cloning
- Treat 'No base branch configured' as a setup signal — script the `but config target` step
- Confirm you are in the root of a GitButler-managed workspace before landing
When it happens
Trigger: Running `but land <branch>` in a repo whose GitButler workspace was never initialized with a target ref: skipped or interrupted onboarding, cloned repo without workspace config, or target cleared while branches remained.
Common situations: New clone where the setup flow was skipped; workspace metadata deleted or partially restored; CI checking out a fresh clone and running land directly; running from a directory that is not the managed repo root.
Related errors
- DefaultTargetNotFound
- No target branch is configured and none could be inferred. R
- `but land` requires an active GitButler workspace (`gitbutle
- Failed to determine Gerrit target branch
- When using OpenRouter, you must provide a valid API key
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/2698d37c28971696.
Report an issue: GitHub.