cjpais/Handy · critical
Failed to initialize store
Error message
Failed to initialize store
What it means
Panic when tauri-plugin-store's app.store(path) fails while reading settings in get_settings. The store builder errors on I/O — creating or opening the settings store file under the app data dir (permission denied, read-only directory, invalid path, disk full). Because get_settings is called at startup, from the idle watcher every 10 seconds, and from many commands, this expect can fire long after launch whenever the filesystem state changes.
Solutions
- Check writability and permissions of the app data dir and the settings store file
- Free disk space and exclude the app data dir from sync/AV real-time scanning to remove locks
- If the store file itself is corrupt, delete it to regenerate defaults (settings reset) — note parse errors are salvaged, only I/O errors hit this expect
- Include the store path and underlying error in the panic message to identify the failing location
Example fix
// before
let store = app
.store(crate::portable::store_path(SETTINGS_STORE_PATH))
.expect("Failed to initialize store");
// after — name the path and cause in the panic
let path = crate::portable::store_path(SETTINGS_STORE_PATH);
let store = app
.store(path.clone())
.unwrap_or_else(|e| panic!("Failed to initialize store at {path:?}: {e}")); Defensive patterns
Strategy: fallback
Validate before calling
// Probe store writability once at startup rather than expecting on every read
let store = match app.store(crate::portable::store_path(SETTINGS_STORE_PATH)) {
Ok(s) => s,
Err(e) => {
log::error!("settings store unavailable: {e}");
return AppSettings::default();
}
}; Try / catch
match app.store(path) {
Ok(store) => store,
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {
// surface a repair action (fix permissions / free space) and use defaults for this session
AppSettings::default()
}
Err(e) => {
log::error!("store init failed: {e}");
AppSettings::default()
}
} Prevention
- Open the settings store once at startup and cache the handle instead of re-opening on every read (the idle watcher re-runs get_settings every 10 s)
- Probe store writability during onboarding and surface a repair screen
- Keep the app data dir outside sync/AV-managed folders
When it happens
Trigger: Any get_settings call where the store file cannot be created or opened: unwritable app data dir, file locked by another process, full disk, or a broken path in portable mode.
Common situations: App data permissions damaged after OS migration; portable mode pointing at an unwritable path; AV/sync agents locking the JSON store; disk filling up while the app runs; path length/charset issues on Windows.
Related errors
- Failed to initialize model manager
- Device index ( ) cannot host a model
- error while building tauri application
- failed to create cancel item
- failed to create check updates item
AI-assisted analysis of cjpais/Handy@fbd4e15fa1 (2026-08-17).
Data as JSON: /api/errors/d5e12797c0fbb2a8.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/settings.rs:1017
self.post_process_providers
.iter_mut()
.find(|provider| provider.id == provider_id)
}
}
/// Startup entry point. Same load-or-create/salvage/migrate behavior as
/// `get_settings`; kept as a named alias for call-site clarity, plus a
/// one-time debug dump of the loaded settings.
pub fn load_or_create_app_settings(app: &AppHandle) -> AppSettings {
let settings = get_settings(app);
debug!("Loaded settings: {:?}", settings);
settings
}
pub fn get_settings(app: &AppHandle) -> AppSettings {
let store = app
.store(crate::portable::store_path(SETTINGS_STORE_PATH))
.expect("Failed to initialize store");
// Settings reads also persist one-time migrations. Migration helpers are
// idempotent, so this converges after the first read of an older store.
let mut settings = if let Some(settings_value) = store.get("settings") {
let (mut settings, mut updated) =
match serde_json::from_value::<AppSettings>(settings_value.clone()) {
Ok(settings) => (settings, false),
Err(e) => {
warn!("Failed to parse stored settings ({e}); salvaging valid fields");
(salvage_settings(&settings_value), true)
}
};
if apply_settings_migrations(&mut settings, &settings_value) {
updated = true;
}
// Merge in any bindings added since this store was written.View on GitHub (pinned to fbd4e15fa1)