{"record":{"id":"350b69332a4910b9","repo":"gitbutlerapp/gitbutler","slug":"failed-to-join-thread-e-review","errorCode":null,"errorMessage":"Failed to join thread: {e:?}","messagePattern":"Failed to join thread: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-forge/src/review.rs","lineNumber":683,"sourceCode":"            let repo = repo.clone();\n            let storage = storage.clone();\n\n            let pulls = std::thread::spawn(move || {\n                tokio::runtime::Runtime::new()\n                    .map_err(|e| {\n                        anyhow::anyhow!(\n                            \"Failed to create a runtime for the settled-review sweep: {e}\"\n                        )\n                    })?\n                    .block_on(but_github::pr::list_recently_closed(\n                        preferred_account.as_ref(),\n                        &owner,\n                        &repo,\n                        &storage,\n                    ))\n            })\n            .join()\n            .map_err(|e| anyhow::anyhow!(\"Failed to join thread: {e:?}\"))??;\n\n            pulls.into_iter().map(ForgeReview::from).collect()\n        }\n        ForgeName::GitLab => {\n            let preferred_account = preferred_forge_user\n                .as_ref()\n                .and_then(|user| user.gitlab().cloned());\n            let project_id = GitLabProjectId::new(owner, repo);\n            let storage = storage.clone();\n\n            let mrs = std::thread::spawn(move || {\n                tokio::runtime::Runtime::new()\n                    .map_err(|e| {\n                        anyhow::anyhow!(\n                            \"Failed to create a runtime for the settled-review sweep: {e}\"\n                        )\n                    })?\n                    .block_on(but_gitlab::mr::list_recently_closed(","sourceCodeStart":665,"sourceCodeEnd":701,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-forge/src/review.rs#L665-L701","documentation":"In list_recently_settled_reviews (GitHub branch), the worker thread's JoinHandle::join() returned Err, meaning the thread panicked (e.g. the inner Runtime::new().unwrap() or a panic in but_github::pr::list_recently_closed). The panic is rewrapped as this anyhow error.","triggerScenarios":"The spawned GitHub PR-sweep thread panics before returning — unwrap failure on Runtime::new(), a panic inside the GitHub client, or poisoned-thread conditions after another panic.","commonSituations":"Resource exhaustion making runtime creation unwrap-fail; GitHub API returning an unexpected response shape that trips an unwrap; bugs in the client crate.","solutions":["Inspect the Debug payload for the original panic message and location","Replace unwrap() on Runtime::new() with a mapped error so join can propagate a real error","Fix the underlying panic in the forge client (e.g. handle unexpected API responses without panicking)","Avoid the thread+block_on pattern to remove the join/panic indirection"],"exampleFix":"// before\nRuntime::new().unwrap().block_on(...)\n// after\nRuntime::new().map_err(|e| anyhow::anyhow!(\"runtime: {e}\"))?.block_on(...)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match list_recently_settled_reviews(...) {\n    Ok(reviews) => reviews,\n    Err(e) if e.to_string().contains(\"Failed to join thread\") => {\n        tracing::warn!(\"review sweep worker panicked: {e:#}\");\n        Vec::new() // degrade gracefully\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Remove unwrap() calls from spawned workers","Keep workers returning Result so panics never poison the join","Harden forge clients against unexpected API payloads"],"tags":["rust","threading","panic"],"backgroundTag":"thread-interrupted","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}