gitbutlerapp/gitbutler · error · anyhow::Error
Could not restore native GitHub stack membership after the p
Error message
Could not restore native GitHub stack membership after the push failed:
{} What it means
During review updates GitButler first dissolves native GitHub 'stack' membership, pushes, then re-registers stacks via `restore_native_stacks()`. Each `but_github::stacks::create()` failure is collected (formatted with `{err:#}` to flatten context chains), and if any failed the aggregate bail fires after the push already failed — so the repo is back on old refs but GitHub's stack graph may still be dissolved. The inner lines name each failing stack's PR list and cause.
Source
Thrown at crates/but-forge/src/review.rs:2511
preferred_forge_user: &Option<crate::ForgeUser>,
forge_repo_info: &crate::forge::ForgeRepoInfo,
stacks: &[Vec<i64>],
storage: &but_forge_storage::Controller,
) -> Result<()> {
let crate::forge::ForgeRepoInfo { owner, repo, .. } = forge_repo_info;
let preferred_account = preferred_forge_user.as_ref().and_then(|user| user.github());
let mut errors = Vec::new();
for pull_requests in stacks {
if let Err(err) =
but_github::stacks::create(preferred_account, owner, repo, pull_requests, storage).await
{
errors.push(format!("{err:#}"));
}
}
if errors.is_empty() {
Ok(())
} else {
anyhow::bail!(
"Could not restore native GitHub stack membership after the push failed:\n{}",
errors.join("\n")
)
}
}
async fn github_review_bodies(
preferred_account: Option<&but_github::GithubAccountIdentifier>,
owner: &str,
repo: &str,
reviews: &[ForgeReviewUpdate],
storage: &but_forge_storage::Controller,
) -> Result<(Vec<Option<Option<String>>>, Vec<String>)> {
let mut bodies = Vec::with_capacity(reviews.len());
let mut errors = Vec::new();
for review in reviews {
if review.update_description {
bodies.push(Some(review.body.clone()));View on GitHub (pinned to caf1f223d3)
Solutions
- Read the inner error lines: 401/403 points to auth (re-authenticate the GitHub account in GitButler), 403 rate-limit says to wait; other codes name the stack/PRs involved.
- Re-run the push/review update once auth and network are healthy — successful subsequent updates recreate correct stack membership.
- If GitHub still shows dissolved stacks, manually re-stack via the PR UI or `but` forge tooling once all member PRs are open.
- Verify no member PR was closed/merged mid-operation; GitHub refuses stacks containing closed PRs (a restorable stack needs >= 2 open members).
Defensive patterns
Strategy: try-catch
Try / catch
// After the push already failed, a stack-restore failure is best-effort:
// log it, keep the original push error primary, and surface a follow-up action.
match restore_native_stacks(&user, &info, &stacks, &storage).await {
Ok(()) => {}
Err(restore_err) => {
tracing::warn!("{restore_err:#}");
notify_user("GitHub stack membership may be dissolved; re-run sync once re-authenticated to repair");
// do NOT mask the original push failure with restore_err
}
} Prevention
- Check GitHub auth (valid, unexpired token) before starting push/review update flows at all.
- Avoid closing/merging member PRs while a stacked push is in flight; GitHub refuses stacks with closed members.
- Handle secondary rate limits: back off before retrying, don't hammer stacks::create after a failed push.
- After any occurrence, verify GitHub PR stacking state once connectivity/auth is confirmed and repair by re-running sync.
When it happens
Trigger: A push failure while updating reviews, followed by a rollback where re-creating GitHub stack membership fails too — expired OAuth token, rate limiting, network drop, or GitHub refusing a stack that now contains a closed PR.
Common situations: Token revoked or expired mid-session; GitHub API secondary rate limits during rapid push/retry cycles; one PR in the stack closed/merged while the push was in flight; flaky connectivity.
Related errors
- Could not restore all review targets after the push failed:
- push failed
- push failed after {MAX_RETRIES} attempts
- Branch `{}` is pushed, but its remote ancestry does not matc
- Bitbucket request failed: {}
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/0e9f6126332f46c1.
Report an issue: GitHub.