libnyanpasu/clash-nyanpasu · error
failed to open storage: {e}
Error message
failed to open storage: {e} What it means
After extracting hotkey strings from config.yaml, the migration opens the KV storage database via Storage::try_new(storage_path) to write the migrated values. If the storage backend cannot be created or opened (I/O error, corrupt database file, locked file, bad path), this error aborts the migration before any hotkeys are written.
Source
Thrown at backend/tauri/src/core/migration/modules/storage.rs:100
let Some(hotkeys_value) = config.get(&hotkeys_key).cloned() else {
return Ok(());
};
let Some(hotkeys) = hotkeys_value.as_sequence() else {
return Ok(());
};
let hotkey_strings: Vec<String> = hotkeys
.iter()
.filter_map(|value| value.as_str().map(ToString::to_string))
.collect();
if !hotkey_strings.is_empty() {
let storage_path = ctx.storage_path();
if let Some(parent) = storage_path.parent() {
std::fs::create_dir_all(parent)?;
}
let storage = Storage::try_new(&storage_path)
.map_err(|e| anyhow::anyhow!("failed to open storage: {e}"))?;
storage
.set_item("hotkeys", &hotkey_strings)
.map_err(|e| anyhow::anyhow!("failed to save hotkeys: {e}"))?;
// Note: registration is intentionally NOT done here. This migration
// runs in a separate `migrate` subprocess with no Tauri app handle, so
// `Hotkey::update` would fail; `Hotkey::init` reads the migrated value
// from KV storage at app startup instead.
tracing::info!("migrated {} hotkeys to KV storage", hotkey_strings.len());
}
config.remove(&hotkeys_key);
let new_config = serde_yaml::to_string(&config)
.map_err(|e| anyhow::anyhow!("failed to serialize config: {e}"))?;
crate::core::migration::fs::atomic_write(&config_path, new_config.as_bytes())?;
Ok(())View on GitHub (pinned to f7dbce2997)
Solutions
- Close all running Nyanpasu instances (and the migrate subprocess) so the storage file is not locked, then retry.
- Check {e} for the underlying cause: fix directory permissions or free disk space at the storage path.
- If the KV database file is corrupt, back it up and remove/rename it so a fresh storage is created (other stored settings may need re-entry).
- Exclude the app data directory from antivirus/controlled-folder-access interference and verify the path is writable.
- Re-run the migration after remediation; config.yaml was not modified on this failure path.
Example fix
// before
let storage = Storage::try_new(&storage_path)
.map_err(|e| anyhow::anyhow!("failed to open storage: {e}"))?;
// after
let storage = Storage::try_new(&storage_path)
.with_context(|| format!("failed to open storage at {} — close running instances and check permissions", storage_path.display()))?; Defensive patterns
Strategy: try-catch
Validate before calling
fn storage_path_writable(p: &Path) -> Result<(), String> {
if let Some(parent) = p.parent() {
std::fs::create_dir_all(parent).map_err(|e| format!("mkdir: {e}"))?;
}
let probe = p.with_extension("write-probe");
std::fs::write(&probe, b"").map_err(|e| format!("not writable: {e}"))?;
std::fs::remove_file(&probe).map_err(|e| format!("cleanup: {e}"))?;
Ok(())
} // also ensure no other app instance is running and holds the DB lock Type guard
null
Try / catch
let storage = match Storage::try_new(&storage_path) {
Ok(s) => s,
Err(e) => {
eprintln!("close running Nyanpasu instances and check permissions at {}: {e}", storage_path.display());
return Err(anyhow::anyhow!("failed to open storage: {e}"));
}
}; Prevention
- Ensure the app and migrate subprocess are not running concurrently with the migration
- Verify the app-data directory is writable and excluded from controlled-folder access/AV
- Back up the KV storage file before migrating; replace it if corrupt
- Check free disk space on the volume before running migrations
When it happens
Trigger: Storage::try_new fails because the storage directory cannot be used: parent dir creation succeeded but the DB file is corrupt, locked by another process (a running app instance holds it), permissions deny access, or the path is invalid/on a full disk.
Common situations: Nyanpasu still running and holding the storage lock during migration; corrupted KV database from a previous crash; read-only install directory or antivirus blocking file creation; network/roaming profile paths unavailable.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- failed to save hotkeys: {e}
- failed to parse config: {e}
- result.error
- cannot repair typed clash config before split_legacy_config
- unrecognized typed config migration state: existing {} is ne
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/ca4a3df37b5801d9.
Report an issue: GitHub.