gitbutlerapp/gitbutler · error
Failed to fetch review
Error message
Failed to fetch review {review_number}: thread panicked: {e:?} What it means
After `get_forge_review` spawns a thread that runs the async fetch with `runtime.block_on`, the thread's `join()` result is mapped through this error. `JoinError` means the worker thread panicked (or was cancelled), so the review fetch aborted abnormally. The panic payload is included with `{e:?}` for diagnosis; a panic here usually indicates an unexpected bug inside the forge client rather than a normal API failure.
Solutions
- Read the panic payload in the error message to identify the panicking location and fix or report the underlying bug.
- Re-run the command; a transient panic in a dependent crate may not reproduce.
- Capture the exact forge/review data that triggered it and file an issue with the payload.
- As a workaround, fetch the review via the forge web UI to unblock, then upgrade the library once fixed.
Defensive patterns
Strategy: try-catch
Try / catch
match get_forge_review(db, storage, preferred_user, review_number) {
Ok(review) => review,
Err(e) if e.to_string().contains("thread panicked") => {
log::error!("forge review fetch panicked: {e}");
// report bug; optionally retry once
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Treat this as a library bug: capture the panic payload and file an issue
- Keep the library and its tokio/forge dependencies up to date
- Avoid running fetches during process shutdown
When it happens
Trigger: Any call to `get_forge_review` where the spawned thread panics during `get_forge_review_inner` (e.g. an unwrapped Option/Result, slice index panic, assertion inside the async forge client), or thread cancellation on shutdown.
Common situations: Bug in a forge API response handling path that assumes a field exists; running on a platform where a dependency panics on unusual input; process shutdown racing the fetch.
Related errors
- a committed transaction always materializes a workspace
- anchor is always present in the order at this point
- another pre-commit hook is already using the repository…
- Archive progress counter thread panicked
- AtSegment anchor always has oldest commit resolved
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/f8ebf829c9bfaccd.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-forge/src/review.rs:2349
let storage = storage.clone();
let review = std::thread::spawn(move || {
let runtime = tokio::runtime::Runtime::new().map_err(|e| {
anyhow::anyhow!(
"Failed fetch review {review_number}: failed to create Tokio runtime: {e}"
)
})?;
runtime.block_on(get_forge_review_inner(
&preferred_forge_user,
&forge_repo_info,
review_number,
&storage,
))
})
.join()
.map_err(|e| {
anyhow::anyhow!("Failed to fetch review {review_number}: thread panicked: {e:?}")
})??;
// Cache the review and ignore any issues, if any.
crate::db::upsert_review(db, &review).ok();
Ok(review)
}
/// How to merge a review on the forge. GitHub honours all three;
/// other forges fall back to their default merge strategy when the
/// caller asks for `Squash`/`Rebase`.
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[cfg_attr(feature = "export-schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "lowercase")]
pub enum ReviewMergeMethod {
#[default]
Merge,
Squash,
Rebase,View on GitHub (pinned to 58e5313667)