tauri-apps/tauri · critical
state not found for type
Error message
state not found for type {} What it means
State<'_, T>::get retrieves managed state of type T registered via Manager::manage. If no state of that type was ever managed on the app, try_get returns None and get panics with the type name. It is an unrecoverable programmer error: state must be registered before the app runs the event loop.
Solutions
- Register the state before running: app.manage(MyState::default())
- Use try_get::<T>() to handle absence gracefully instead of panicking
- Verify the exact type T matches the one passed to manage (generics are compared by TypeId)
Example fix
// before
let state = app.state::<Db>();
// after
fn main() -> tauri::Result<()> {
tauri::Builder::default()
.setup(|app| { app.manage(Db::connect()?); Ok(()) })
.run(tauri::generate_context!())
} Defensive patterns
Strategy: validation
Validate before calling
if app.try_state::<MyState>().is_none() {
eprintln!("MyState not managed; call app.manage(MyState::default()) before run");
} Type guard
fn has_state<T: Send + Sync + 'static>(app: &tauri::AppHandle) -> bool {
app.try_state::<T>().is_some()
} Try / catch
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| app.state::<MyState>()))
.map_err(|_| anyhow::anyhow!("state <MyState> not managed")) Prevention
- Register all state in .setup() or before .run()
- Use try_state where absence is plausible
- Match manage() types exactly (watch generics)
When it happens
Trigger: Calling app.state::<MyState>() or window.state::<T>() when Manager::manage(MyState) / manage was never called, or called after .run() started, or on a different T than what was managed.
Common situations: Forgetting to call .manage(MyState::default()) in setup or before run; managing a different generic instantiation (e.g. HashMap<String, i32> vs HashMap<i32, i32>); accessing state in a plugin before it is initialized; tests spawning the app without setup.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Failed to render template
- invalid permission identifier
- missing command scope for key
- Not a CheckMenuItem
- Not a MenuItem
AI-assisted analysis of tauri-apps/tauri@460ec35447 (2026-09-18).
Data as JSON: /api/errors/f14f2178b66059fe.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tauri/src/state.rs:145
}
/// SAFETY: Calling this method will move the `value`,
/// which will cause references obtained through [Self::try_get] to dangle.
pub(crate) unsafe fn unmanage<T: Send + Sync + 'static>(&self) -> Option<T> {
let mut map = self.map.lock().unwrap();
let type_id = TypeId::of::<T>();
let state = map.remove(&type_id)?;
let value = state
.downcast::<T>()
.expect("the type of the key should be same as the type of the value");
Some(*value)
}
/// Gets the state associated with the specified type.
pub fn get<T: 'static>(&self) -> State<'_, T> {
self
.try_get()
.unwrap_or_else(|| panic!("state not found for type {}", std::any::type_name::<T>()))
}
/// Gets the state associated with the specified type.
pub fn try_get<T: 'static>(&self) -> Option<State<'_, T>> {
let map = self.map.lock().unwrap();
let type_id = TypeId::of::<T>();
let state = map.get(&type_id)?;
let value = state
.downcast_ref::<T>()
.expect("the type of the key should be same as the type of the value");
// SAFETY: We ensure the lifetime of `value` is the same as [StateManager] and `value` will not be mutated/moved.
let v_ref = unsafe { &*(value as *const T) };
Some(State(v_ref))
}
}
// Ported from https://github.com/SergioBenitez/state/blob/556c1b94db8ce8427a0e72de7983ab5a9af4cc41/tests/main.rs
#[cfg(test)]View on GitHub (pinned to 460ec35447)