tauri-apps/tauri · error
poisoned window resources table
Error message
poisoned window resources table
What it means
Window implements Manager::resources_table() by locking its own std::sync::Mutex around the ResourceTable and calling .expect("poisoned window resources table"). Rust poisons a mutex when a thread panics while holding it, making every subsequent lock fail. This panic therefore reports that an earlier panic poisoned the Window's resource table; the message appears on the next resource access and repeats for every later one until the process ends.
Source
Thrown at crates/tauri/src/window/mod.rs:1072
fn hash<H: Hasher>(&self, state: &mut H) {
self.window.label.hash(state)
}
}
impl<R: Runtime> Eq for Window<R> {}
impl<R: Runtime> PartialEq for Window<R> {
/// Only use the [`Window`]'s label to compare equality.
fn eq(&self, other: &Self) -> bool {
self.window.label.eq(&other.window.label)
}
}
impl<R: Runtime> Manager<R> for Window<R> {
fn resources_table(&self) -> MutexGuard<'_, ResourceTable> {
self
.resources_table
.lock()
.expect("poisoned window resources table")
}
}
impl<R: Runtime> ManagerBase<R> for Window<R> {
fn manager(&self) -> &AppManager<R> {
&self.manager
}
fn manager_owned(&self) -> Arc<AppManager<R>> {
self.manager.clone()
}
fn runtime(&self) -> RuntimeOrDispatch<'_, R> {
RuntimeOrDispatch::Dispatch(self.window.dispatcher.clone())
}
fn managed_app_handle(&self) -> &AppHandle<R> {
&self.app_handleView on GitHub (pinned to 52e4b6e71d)
Solutions
- Enable RUST_BACKTRACE=1 and find the FIRST panic in the log — it is the actual poisoner; this expect is downstream noise.
- Remove every potential panic from Resource::drop and from code paths holding the resources_table() guard (replace unwrap/expect with error returns or logging).
- Keep guards short-lived: fetch the Arc, drop the guard, then do fallible work.
- Restart the application once fixed — the poisoned mutex never recovers in-process.
Example fix
// before: unwrap inside Drop poisons the window resources table
impl Resource for TempBuffer {
fn drop(&mut self) {
std::fs::remove_file(&self.path).expect("temp file removed");
}
}
// after: Drop must not panic
impl Resource for TempBuffer {
fn drop(&mut self) {
if let Err(e) = std::fs::remove_file(&self.path) {
log::warn!("failed to remove temp file {}: {e}", self.path.display());
}
}
} Defensive patterns
Strategy: try-catch
Try / catch
use std::panic::{catch_unwind, AssertUnwindSafe};
// menu-independent guard: wrap resource-table access on Window so a
// poisoned mutex degrades gracefully instead of crashing the thread
match catch_unwind(AssertUnwindSafe(|| window.resources_table())) {
Ok(table) => { /* use the table */ }
Err(_) => {
log::error!("Window resource table poisoned — restart required");
}
} Prevention
- Keep Drop impls of custom resources free of unwrap/expect and I/O panics.
- Log the first panic via std::panic::set_hook so poisoning is diagnosable from the real root cause.
- Scope resource-table guards to the shortest possible block; never across await points or fallible calls.
- Audit commands that look up resources by rid and return Result instead of unwrapping.
When it happens
Trigger: Any panic occurring while a thread holds this Window's resources-table mutex: a panicking Resource::drop (drops run while the table lock is held), a panic in plugin resource registration/lookup (fs, http), or a command/event handler that panics while holding a resources_table() guard. The 'poisoned window resources table' panic then fires on the next resource-related IPC for this Window.
Common situations: Custom resource types with panicking Drop impls; apps that stream large files and hit a mid-stream panic, after which all resource IPC on that window crashes; tauri/plugin version bumps that altered drop order; unwrapping resource lookups by rid in commands.
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/cc3fa7fad2a32e5e.
Report an issue: GitHub.