tauri-apps/tauri · error
poisoned window resources table
Error message
poisoned window resources table
What it means
WebviewWindow implements Manager::resources_table() by locking the inner Webview's ResourceTable mutex and calling .expect("poisoned window resources table"). A std::sync::Mutex becomes poisoned when a thread panics while holding it; all later locks then fail. So this panic on a WebviewWindow means some earlier panic poisoned the shared webview's resource table — the expect is the follow-on crash, not the original fault. Because Webview and WebviewWindow share the same table, poisoning through either type breaks resource IPC for both.
Source
Thrown at crates/tauri/src/webview/webview_window.rs:2795
/// webview_window.unlisten(handler);
///
/// Ok(())
/// });
/// ```
fn unlisten(&self, id: EventId) {
self.manager().unlisten(id)
}
}
impl<R: Runtime> Emitter<R> for WebviewWindow<R> {}
impl<R: Runtime> Manager<R> for WebviewWindow<R> {
fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {
self
.webview
.resources_table
.lock()
.expect("poisoned window resources table")
}
}
impl<R: Runtime> ManagerBase<R> for WebviewWindow<R> {
fn manager(&self) -> &AppManager<R> {
self.webview.manager()
}
fn manager_owned(&self) -> Arc<AppManager<R>> {
self.webview.manager_owned()
}
fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
self.window.runtime()
}
fn managed_app_handle(&self) -> &AppHandle<R> {
self.webview.managed_app_handle()View on GitHub (pinned to 52e4b6e71d)
Solutions
- Run with RUST_BACKTRACE=1 and locate the FIRST panic — that is what poisoned the lock; this message is only the second failure.
- Make every Resource::drop and every block holding a resources_table() guard panic-free: replace unwrap/expect with logged error handling.
- Narrow lock scopes: clone Arcs out of the table and drop the guard before doing anything fallible.
- Restart the app after the fix — poisoning is permanent for the process; there is no un-poison API on these locks.
Example fix
// before: command panics while a resources_table() guard is alive,
// poisoning the table shared by Webview and WebviewWindow
#[tauri::command]
fn read_stream(state: tauri::State<AppState>, rid: u32) -> Vec<u8> {
let table = state.app.webview_window("main").unwrap().resources_table();
let res = table.get::<MyStream>(rid).unwrap(); // panics -> poisons
res.read_all()
}
// after: no guard held across fallible lookups, no unwrap
#[tauri::command]
fn read_stream(app: tauri::AppHandle, rid: u32) -> Result<Vec<u8>, String> {
let win = app.webview_window("main").ok_or("window missing")?;
let stream = {
let table = win.resources_table();
table.get::<MyStream>(rid).map_err(|e| e.to_string())?
}; // guard dropped here
stream.read_all().map_err(|e| e.to_string())
} Defensive patterns
Strategy: try-catch
Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
// WebviewWindow shares the inner webview's resource table; a poisoned
// table panics here — contain and recover by rebuilding the window
match catch_unwind(AssertUnwindSafe(|| webview_window.resources_table())) {
Ok(table) => { /* safe to use */ }
Err(_) => {
log::error!("WebviewWindow resource table poisoned — re-create the window/webview");
}
} Prevention
- Make all custom Resource::drop impls panic-free (log instead of unwrap/expect).
- Add a startup panic hook that logs the first panic — that is the real poisoner; 'poisoned window resources table' is the follow-on symptom.
- Do not hold resources_table() guards across ?-propagating or unwrapping code; extract Arcs and drop guards early.
- When upgrading tauri or fs/http plugins, re-test long-running resource flows (streams, downloads) for panics that poison the shared table.
When it happens
Trigger: A panic anywhere while the inner webview's resource-table mutex is held — most commonly a panicking Resource::drop (resources are destroyed while the table lock is held), a panic in a plugin registering/removing resources (fs streams, http response bodies), or a panicking command that obtained a resources_table() guard — then any later call that touches resources through the WebviewWindow (invoke on commands using taururi-plugin-fs/http, resource resolution by rid).
Common situations: Custom Resource impls with unwrap/expect in Drop; file-streaming apps that panic mid-transfer and then crash on every subsequent resource IPC; version upgrades of tauri or resource-using plugins changing drop/registration order; panics inside event handlers or commands that walk the resource table.
Related errors
- poisoned window resources table
- poisoned window resources table
- poisoned window
- failed to read resource file name
- failed to read resource folder name
AI-assisted analysis of tauri-apps/tauri@52e4b6e71d (2026-08-20).
Data as JSON: /api/errors/69ea007a96d6c0b4.
Report an issue: GitHub.