gitbutlerapp/gitbutler · error

Could not restore all review targets after the push failed

Error message

Could not restore all review targets after the push failed:
{}

What it means

After a push fails, the code attempts to restore review targets (e.g. GitHub native stack membership) that were dissolved during a flattening operation. If any restoration step failed, all collected error messages are joined and thrown as one aggregate error, since review targets could not be fully recovered.

Solutions

  1. Read the aggregated error body to see which specific restorations failed
  2. Fix the underlying push failure (auth, network, remote permissions) and push successfully — native membership will be recreated on the next successful push
  3. Recreate the dissolved stacks manually if needed, then retry review creation
Defensive patterns

Strategy: try-catch

Validate before calling

await ensureRemoteReachable(remoteUrl); // verify auth/network before review-creating push

Try / catch

try {
  await createReview(projectId, opts);
} catch (e) {
  if (String(e).startsWith('Could not restore all review targets')) {
    logAggregateErrors(e.message.split('\n'));
    // next successful push recreates native membership
    await retryPush(projectId);
  } else throw e;
}

Prevention

When it happens

Trigger: A push triggered as part of creating a review fails, and subsequent restoration of dissolved stacks / native GitHub stack membership also reports errors.

Common situations: Network failure or permission error during push; GitHub API errors while restoring PR/stack membership; repo in a partially-migrated state after a failed review creation.

Related errors


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

Appendix: source

Thrown at crates/but-api/src/legacy/forge.rs:1881

            Some(review.target_branch.clone()),
        )
        .await
        {
            errors.push(format!(
                "Failed to restore review #{} to `{}`: {err}",
                review.number, review.target_branch
            ));
        }
    }
    if !errors.is_empty() {
        if !flattening.dissolved_stacks.is_empty() {
            errors.push(
                "Native GitHub stack membership was not restored; the next successful push will \
                 recreate it."
                    .to_string(),
            );
        }
        anyhow::bail!(
            "Could not restore all review targets after the push failed:\n{}",
            errors.join("\n")
        )
    }
    if flattening.dissolved_stacks.is_empty() {
        return Ok(());
    }

    let (storage, forge_repo_info, preferred_forge_user) = {
        let ctx = ctx.into_thread_local();
        let project_meta = ctx.project_meta()?;
        let repo = ctx.repo.get()?;
        let (forge_repo_info, _) = base_and_push_repo_info(&project_meta, &repo)?;
        (
            but_forge_storage::Controller::from_path(but_path::app_data_dir()?),
            forge_repo_info,
            ctx.legacy_project.preferred_forge_user.clone(),
        )

View on GitHub (pinned to 58e5313667)