gitbutlerapp/gitbutler · error
Refusing to land ` ` with --whole-stack: it is not the top…
Error message
Refusing to land `{branch}` with --whole-stack: it is not the top of its stack. --whole-stack lands the entire stack; name its top segment `{top}` instead. What it means
`validate_branch_landing` refuses a `--whole-stack` land when the target branch is not the topmost segment of its stack but a named segment sits above it. `--whole-stack` is defined to land the entire stack, and landing a mid-stack branch that way would strand the commits above it, so GitButler rejects the request and names the actual top segment to use instead.
Solutions
- Land the named top segment instead: `but land <top-segment> --whole-stack` (the error message names it).
- Drop or rebase off the segments above first, then re-run `but land <branch> --whole-stack`.
- Land without `--whole-stack` if you only intend to publish this branch's commits.
Example fix
// before but land middle-branch --whole-stack // refused: not top of stack // after but land top-branch --whole-stack # lands the entire stack including middle-branch
Defensive patterns
Strategy: validation
Validate before calling
// before landing with --whole-stack, verify the branch is the stack top
const stack = await api.listStacks();
const s = stack.find(s => s.branches.includes(branch));
const isTop = s.branches[s.branches.length - 1] === branch;
if (!isTop) throw new Error(`Land the top segment ${s.branches.at(-1)} with --whole-stack instead`); Type guard
function isStackTop(branch: string, stackBranches: string[]): boolean {
return stackBranches[stackBranches.length - 1] === branch;
} Try / catch
try {
await api.land(branch, { wholeStack: true });
} catch (e) {
const m = String(e).match(/name its top segment `([^`]+)`/);
if (m) await api.land(m[1], { wholeStack: true }); // retry with the named top segment
else throw e;
} Prevention
- Run `but status` (or list the stack) to confirm branch position before a whole-stack land.
- Only use --whole-stack from the top of a stack; land bottom segments individually otherwise.
- Automate land scripts to resolve the stack top dynamically rather than hardcoding a branch name.
When it happens
Trigger: Calling `branch_land` with `whole_stack: true` (CLI `but land <branch> --whole-stack`) where `scan.has_upper` is true and `scan.upper_segments` has a named first segment — i.e. the branch has a segment above it in the same stack.
Common situations: Working in a stacked-branch workflow, forgetting that the stack has more segments on top; a branch ref above was renamed so the developer assumes their branch is the top; scripting lands on a fixed branch name that is no longer the stack top.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Refusing to land ` `: it is stacked on top of other…
- Aborting due to empty branch name
- Cannot land ` `: it would publish conflicted commit ( )…
- Refusing to land ` `: commit(s) on unnamed segment(s) below…
- Refusing to land ` ` with --whole-stack: it is not the top…
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/acc7ea1fdc37f5c2.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-api/src/land/mod.rs:411
/// commits in any segment that would be published (the same guard `but push` applies before
/// sending commits to a remote). All computed from the graph workspace, not stack projections.
/// Returns the named lower segments that land together with `branch` — non-empty only for a
/// validated `--whole-stack` land.
fn validate_branch_landing(
ctx: &mut Context,
branch: &str,
target_display: &str,
whole_stack: bool,
) -> anyhow::Result<Vec<String>> {
let Some(scan) = scan_stack(ctx, branch)? else {
return Ok(Vec::new());
};
if whole_stack && scan.has_upper {
// Judge "top of the stack" by position, not by names: a segment whose branch ref was
// deleted still holds commits that "land the entire stack" would have to include.
if let Some(top) = scan.upper_segments.first() {
bail!(
"Refusing to land `{branch}` with --whole-stack: it is not the top of its stack. \
--whole-stack lands the entire stack; name its top segment `{top}` instead.",
);
}
bail!(
"Refusing to land `{branch}` with --whole-stack: it is not the top of its stack — \
unnamed segment(s) with commits sit above it (their branch refs no longer exist), so \
landing `{branch}` would not land the entire stack.",
);
}
// Key off the commits below, not the segment names: segments whose branch ref was deleted are
// unnamed but their commits would be published all the same.
let publishes_below = scan.commits_below > 0 || !scan.lower_segments.is_empty();
if publishes_below && !whole_stack {
if scan.lower_segments.is_empty() {
bail!(
"Refusing to land `{branch}`: {} commit(s) on unnamed segment(s) below it would \
also be published to {target_display}. Pass --whole-stack to land `{branch}` \View on GitHub (pinned to 58e5313667)