tauri-apps/tauri · error · InvokeError
state not managed for field `{}` on command `{}`. You must c
Error message
state not managed for field `{}` on command `{}`. You must call `.manage()` before using this command What it means
Tauri commands can request managed state via a State<'_, T> parameter. CommandArg::from_command looks the value up by TypeId in the state container; if nothing of exactly that type was registered with Builder::manage/App::manage beforehand, try_get returns None and the command invocation is rejected with this error, naming the state field and the command.
Source
Thrown at crates/tauri/src/state.rs:63
}
impl<T: PartialEq> PartialEq for State<'_, T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for State<'_, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("State").field(&self.0).finish()
}
}
impl<'r, 'de: 'r, T: 'static, R: Runtime> CommandArg<'de, R> for State<'r, T> {
/// Grabs the [`State`] from the [`CommandItem`]. This will never fail.
fn from_command(command: CommandItem<'de, R>) -> Result<Self, InvokeError> {
command.message.state_ref().try_get().ok_or_else(|| {
InvokeError::from_anyhow(anyhow::anyhow!(
"state not managed for field `{}` on command `{}`. You must call `.manage()` before using this command",
command.key, command.name
))
})
}
}
// Taken from: https://github.com/SergioBenitez/state/blob/556c1b94db8ce8427a0e72de7983ab5a9af4cc41/src/ident_hash.rs
// This is a _super_ stupid hash. It just uses its input as the hash value. This
// hash is meant to be used _only_ for "prehashed" values. In particular, we use
// this so that hashing a TypeId is essentially a noop. This is because TypeIds
// are already unique integers.
#[derive(Default)]
struct IdentHash(u64);
impl std::hash::Hasher for IdentHash {
fn finish(&self) -> u64 {
self.0View on GitHub (pinned to 2f1cd75b0f)
Solutions
- Register the state before the app runs: tauri::Builder::default().manage(MyState::new())...invoke_handler(...).run(...)
- Make the managed type exactly match the command parameter, including Mutex<>/RwLock<> wrappers ('static, Send + Sync)
- If timing is the issue, move manage() into Builder::setup (or onto the builder before run) so it always precedes the first invoke
- For genuinely optional state, fetch with app.try_state::<T>() and handle None instead of failing
Example fix
// before: command needs State<AppStore> but nothing was managed
#[tauri::command]
fn items(state: State<AppStore>) -> Vec<Item> { state.all() }
// after
fn main() {
tauri::Builder::default()
.manage(AppStore::new())
.invoke_handler(tauri::generate_handler![items])
.run(tauri::generate_context!())
.unwrap();
} Defensive patterns
Strategy: validation
Type guard
// Rust: check state is managed before invoking command logic
fn state_ready<T: Send + Sync + 'static>(app: &tauri::AppHandle) -> bool {
app.try_state::<T>().is_some()
} Try / catch
// frontend: distinguish the 'not managed' rejection from other command errors
try {
await invoke('get_items')
} catch (e) {
if (String(e).includes('state not managed')) {
// initialization order bug: ensure .manage() runs before first invoke; surface a setup hint
} else throw e
} Prevention
- Register all managed state in one place on the Builder (or first thing in setup) before invoke_handler runs
- Keep a single source-of-truth list of managed types and review it when adding State parameters to commands
- Match wrapper types exactly: manage(Mutex<T>::new(..)) pairs with State<Mutex<T>>, not State<T>
- Write a startup smoke test that invokes each state-dependent command once
When it happens
Trigger: Invoking a command from the frontend (invoke('my_command')) whose signature includes a State<'_, T> parameter while the app never called .manage(...) for T; also when the managed type differs from the requested type (e.g. managed Mutex<Store> but requested State<Store>), or when the invoke races ahead of the manage() call in setup.
Common situations: Adding a State parameter to a command but forgetting .manage(); refactoring the type (wrapping in Mutex/RwLock, renaming) so TypeIds no longer match; invoking commands during window creation before setup managed the state.
Related errors
AI-assisted analysis of tauri-apps/tauri@2f1cd75b0f (2026-08-16).
Data as JSON: /api/errors/07e6af003ab96506.
Report an issue: GitHub.