{"record":{"id":"695bd0cf0a9c8b5b","repo":"gitbutlerapp/gitbutler","slug":"panic-while-executing-panic-backtrace-un","errorCode":null,"errorMessage":"panic while executing `{}`: {}\n\npanic backtrace unavailable from hook; conversion backtrace:\n{}","messagePattern":"panic while executing `(.+?)`: (.+?)\n\npanic backtrace unavailable from hook; conversion backtrace:\n(.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-api/src/panic_capture.rs","lineNumber":76,"sourceCode":"            .payload_message\n            .as_deref()\n            .or(payload_message.as_deref())\n            .unwrap_or(\"panic payload was not a string\");\n        let panic_location = snapshot.location.as_deref().unwrap_or(\"<unknown location>\");\n        anyhow::anyhow!(\n            \"panic while executing `{}` on thread '{}' ({}) at {}: {}\\n\\npanic backtrace:\\n{}\",\n            function_name,\n            snapshot.thread_name,\n            snapshot.thread_id,\n            panic_location,\n            panic_message,\n            snapshot.backtrace\n        )\n    } else {\n        let panic_message = payload_message\n            .as_deref()\n            .unwrap_or(\"panic payload was not a string\");\n        anyhow::anyhow!(\n            \"panic while executing `{}`: {}\\n\\npanic backtrace unavailable from hook; conversion backtrace:\\n{}\",\n            function_name,\n            panic_message,\n            std::backtrace::Backtrace::force_capture()\n        )\n    }\n}\n\n/// Installs a hook that captures panic context and then delegates to the previous hook.\n/// Can be called multiple times, but only the first call will install the hook.\npub fn install_panic_hook() {\n    INSTALL_PANIC_HOOK.call_once(|| {\n        let previous_hook = panic::take_hook();\n        panic::set_hook(Box::new(move |panic_info| {\n            capture_panic_info(panic_info);\n            previous_hook(panic_info);\n        }));\n    });","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but-api/src/panic_capture.rs#L58-L94","documentation":"The degraded variant of GitButler's panic capture: the panic payload was converted into an error, but no hook snapshot existed, so thread name, panic location, and the hook backtrace are missing; a fresh Backtrace::force_capture() taken at the conversion site is attached instead. It means the same thing (an exported function panicked) with worse diagnostics — typically install_panic_hook() had not run yet, the TLS snapshot was already consumed (nested panic), or the panic happened outside the hooked path.","triggerScenarios":"Panics in but-api functions during early startup or in tests before install_panic_hook() runs; double panics where LAST_PANIC_INFO was already taken; panics on threads where the snapshot failed to record.","commonSituations":"Test harnesses exercising but-api without the hook; initialization-order bugs where an API call precedes hook installation; panics raised while handling another panic.","solutions":["Ensure install_panic_hook() is called before any but-api invocation — it is call_once-safe.","Use the attached conversion backtrace plus the payload message to locate the panic; enable RUST_BACKTRACE=1 for more frames.","Fix the underlying panic exactly as with the snapshot variant.","If nested panics are involved, find the first panic — the second usually hides it."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await gitbutlerApi.workspaceOp();\n} catch (e) {\n  const msg = String(e?.message ?? e);\n  if (msg.includes('panic while executing')) {\n    log.error('rust panic (degraded capture — hook not installed?)', msg);\n    throw new InternalError('internal error, see logs');\n  }\n  throw e;\n}","preventionTips":["Call install_panic_hook() first thing in main() and in test setup.","Avoid invoking exported APIs before initialization completes — 'backtrace unavailable from hook' wording is an init-order smell.","Watch for nested panics; the first panic is the real one."],"tags":["panic","ffi","napi","startup","backtrace"],"backgroundTag":"rust-panic-across-ffi","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}