gitbutlerapp/gitbutler · error

Could not restore native GitHub stack membership after the…

Error message

Could not restore native GitHub stack membership after the push failed:
{}

What it means

After a failed push, the GitHub review code attempts to restore each PR's native stack membership (re-registering PRs into their stacks). Any error from those restore steps is collected; if any occurred, this error bails listing all of them. It indicates cleanup-after-failure also failed, so local and GitHub stack state may be inconsistent.

Solutions

  1. Read the per-error lines in the message to identify which PRs failed to restore
  2. Re-run the stack synchronization (but push / sync) once the API is reachable; the next successful sync recreates the desired stacks
  3. Check the GitHub token's scopes and repo access for the failing PRs
Defensive patterns

Strategy: try-catch

Try / catch

match push_result {
    Err(e) if e.to_string().contains("Could not restore native GitHub stack membership") => {
        log::error!("push failed AND membership restore failed; state may be inconsistent: {e:#}");
        // schedule a re-sync
    }
    other => other?,
}

Prevention

When it happens

Trigger: A push of a stacked-review branch fails, then the restore_native_stack_membership routine errors on one or more PRs (API failures, permission problems, deleted PRs), producing this aggregated bail.

Common situations: GitHub API outages or rate limits during push failure recovery; token lacking rights to update the PRs; PRs closed/deleted concurrently so membership cannot be re-registered.

Related errors


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

Appendix: source

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

    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 58e5313667)