{"record":{"id":"fa8c11fc349788a4","repo":"tauri-apps/tauri","slug":"poisoned-window-resources-table","errorCode":null,"errorMessage":"poisoned window resources table","messagePattern":"poisoned window resources table","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tauri/src/webview/mod.rs","lineNumber":2427,"sourceCode":"\n    Ok(())\n  });\n```\n  \"####\n  )]\n  fn unlisten(&self, id: EventId) {\n    self.manager.unlisten(id)\n  }\n}\n\nimpl<R: Runtime> Emitter<R> for Webview<R> {}\n\nimpl<R: Runtime> Manager<R> for Webview<R> {\n  fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {\n    self\n      .resources_table\n      .lock()\n      .expect(\"poisoned window resources table\")\n  }\n}\n\nimpl<R: Runtime> ManagerBase<R> for Webview<R> {\n  fn manager(&self) -> &AppManager<R> {\n    &self.manager\n  }\n\n  fn manager_owned(&self) -> Arc<AppManager<R>> {\n    self.manager.clone()\n  }\n\n  fn runtime(&self) -> RuntimeOrDispatch<'_, R> {\n    self.app_handle.runtime()\n  }\n\n  fn managed_app_handle(&self) -> &AppHandle<R> {\n    &self.app_handle","sourceCodeStart":2409,"sourceCodeEnd":2445,"githubUrl":"https://github.com/tauri-apps/tauri/blob/52e4b6e71d8632a7e648f866c442e287ecddee34/crates/tauri/src/webview/mod.rs#L2409-L2445","documentation":"Webview implements the Manager trait's resources_table() by locking a std::sync::Mutex around the ResourceTable that tracks Tauri resources (named streams/buffers used by core and plugins such as fs and http). Rust marks a mutex 'poisoned' when any thread panics while holding it, and every later lock fails; Tauri turns that failure into .expect(\"poisoned window resources table\"), so this panic is the symptom of an EARLIER panic, not the root cause. Once poisoned, every subsequent resources_table() call on this Webview panics for the lifetime of the process.","triggerScenarios":"Any panic that occurs while a thread holds this Webview's resources-table mutex, followed by any later access. Typical poisoners: a panicking Resource::drop implementation (the table destroys resources while its lock is held), a panic in plugin code registering or resolving resources (tauri-plugin-fs streams, http bodies), or a command that panics while a MutexGuard from resources_table() is alive. The visible panic then fires on the next resource operation, e.g. an invoke whose command resolves a resource by rid.","commonSituations":"Custom Resource implementations using unwrap/expect/indexing in Drop; long-lived apps streaming files where a mid-stream panic occurs and every later IPC touching resources crashes; upgrades of tauri or resource-using plugins that changed drop order; panics inside commands that iterate the resource table.","solutions":["Reproduce with RUST_BACKTRACE=1 and find the FIRST panic in the logs — that panic poisoned the mutex; this expect is only the second failure.","Audit every Resource::drop and every code path that holds the resources_table() guard for unwrap/expect/indexing that can panic, and make them log errors instead.","Restructure so the lock is not held across fallible work: clone the Arc out of the table and drop the MutexGuard before propagating errors.","Restart the application (or re-create the Webview) after fixing — a poisoned mutex cannot be un-poisoned in-process."],"exampleFix":"// before: panicking Drop runs while the resources-table lock is held,\n// poisoning the mutex for every later resources_table() call\nimpl Resource for MyStream {\n  fn drop(&mut self) {\n    let mut buf = [0u8; 8];\n    self.file.read_exact(&mut buf).expect(\"final read failed\");\n  }\n}\n\n// after: never panic inside Drop — log instead\nimpl Resource for MyStream {\n  fn drop(&mut self) {\n    let mut buf = [0u8; 8];\n    if let Err(e) = self.file.read_exact(&mut buf) {\n      log::error!(\"MyStream final read failed: {e}\");\n    }\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"use std::panic::{catch_unwind, AssertUnwindSafe};\n\n// resources_table() panics when the underlying mutex is poisoned;\n// contain it instead of crashing the calling thread\nmatch catch_unwind(AssertUnwindSafe(|| window.resources_table())) {\n  Ok(table) => { /* use the ResourceTable guard here */ }\n  Err(_) => {\n    log::error!(\"Webview resource table poisoned — re-create the webview\");\n    // e.g. rebuild the webview or signal the user to restart\n  }\n}","preventionTips":["Never panic in Resource::drop implementations — drops run while the table lock is held and poison it.","Install a panic hook (std::panic::set_hook) at startup that logs payload + backtrace, so the ORIGINAL poisoning panic is visible; this expect is only the second failure.","Keep resources_table() guard scopes minimal: clone the Arc out of the table and drop the guard before any fallible work.","Replace unwrap/expect with Result handling in commands and plugin code that touch resources by rid."],"tags":["rust","mutex","poisoning","panic","resources","webview","manager"],"backgroundTag":"mutex-poisoning","analyzedSha":"52e4b6e71d8632a7e648f866c442e287ecddee34","analyzedAt":"2026-08-20T13:59:20.734Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}