gitbutlerapp/gitbutler · error

Could not update all PR targets before native stack…

Error message

Could not update all PR targets before native stack registration:
{}

What it means

Before registering a stack natively on GitHub, the review flow updates each PR's target branch. If any of those per-PR target updates fail, the errors are collected and this bail fires listing them all, aborting before but_github::stacks::finish runs.

Solutions

  1. Inspect each 'PR #N target:' line to see which PRs and why they failed
  2. Fix the underlying cause (permissions, closed PR, API availability) and retry the push/sync
  3. Dissolved membership is expected here; the next successful synchronization recreates the stack, so simply retrying after fixing is safe
Defensive patterns

Strategy: try-catch

Try / catch

match result {
    Err(e) if e.to_string().contains("Could not update all PR targets") => {
        eprintln!("fix target-update causes and retry; membership will be recreated on next sync");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Preparing native stack registration for a multi-PR stack where one or more PR base/target updates fail (API error, permission denied, PR closed, rate limit), collecting 'PR #N target: <err>' entries.

Common situations: Branch protection or missing write access preventing target changes; PRs force-closed by a teammate mid-operation; GitHub API 5xx or rate limiting during batch updates.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/e985ab4e2f456910. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-forge/src/review.rs:3135

            continue;
        }
        let params = but_github::UpdatePullRequestParams {
            owner,
            repo,
            pr_number: review.number,
            title: None,
            body: None,
            base: Some(target_branch),
            state: None,
        };
        if let Err(err) = but_github::pr::update(preferred_account, params, storage).await {
            target_errors.push(format!("PR #{} target: {err}", review.number));
        }
    }
    if !target_errors.is_empty() {
        // Dissolved membership stays dissolved here; the next successful synchronization sees
        // no registered stacks and recreates the desired one.
        anyhow::bail!(
            "Could not update all PR targets before native stack registration:\n{}",
            target_errors.join("\n")
        );
    }

    but_github::stacks::finish(preferred_account, owner, repo, &prepared.plan, storage).await?;

    // GitHub now renders the native stack, so GitButler's description footer is redundant.
    // Strip any existing footers regardless of the configured description mode, which only
    // applies to footer-based stacking. User text is preserved, and reviews whose body would
    // not change are skipped entirely — unless the caller supplied a new description to push.
    for (review, current_body) in reviews.iter().zip(bodies) {
        let Some(current_body) = current_body else {
            continue;
        };
        let updated_body = update_body_with_mode(
            current_body.as_deref(),
            review.number,

View on GitHub (pinned to 58e5313667)