{"record":{"id":"9b00ad858606869f","repo":"0x192/universal-android-debloater","slug":"could-not-write-config-file-to-disk","errorCode":null,"errorMessage":"Could not write config file to disk!","messagePattern":"Could not write config file to disk!","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/core/config.rs","lineNumber":70,"sourceCode":"#[dynamic]\nstatic CONFIG_FILE: PathBuf = CONFIG_DIR.join(\"config.toml\");\n\nimpl Config {\n    pub fn save_changes(settings: &Settings, device_id: &String) {\n        let mut config = Self::load_configuration_file();\n        if let Some(device) = config\n            .devices\n            .iter_mut()\n            .find(|x| x.device_id == *device_id)\n        {\n            *device = settings.device.clone();\n        } else {\n            debug!(\"config: New device settings saved\");\n            config.devices.push(settings.device.clone());\n        }\n        config.general = settings.general.clone();\n        let toml = toml::to_string(&config).unwrap();\n        fs::write(&*CONFIG_FILE, toml).expect(\"Could not write config file to disk!\");\n    }\n\n    pub fn load_configuration_file() -> Self {\n        match fs::read_to_string(&*CONFIG_FILE) {\n            Ok(s) => match toml::from_str(&s) {\n                Ok(config) => return config,\n                Err(e) => error!(\"Invalid config file: `{}`\", e),\n            },\n            Err(e) => error!(\"Failed to read config file: `{}`\", e),\n        }\n        error!(\"Restoring default config file\");\n        let toml = toml::to_string(&Self::default()).unwrap();\n        fs::write(&*CONFIG_FILE, toml).expect(\"Could not write config file to disk!\");\n        Self::default()\n    }\n}\n","sourceCodeStart":52,"sourceCodeEnd":87,"githubUrl":"https://github.com/0x192/universal-android-debloater/blob/11f27c671cba278d71296cdef4c5a5dba06add5e/src/core/config.rs#L52-L87","documentation":"Config::save_changes serializes the app Config struct to TOML and writes it to the static CONFIG_FILE path (CONFIG_DIR/config.toml) using fs::write(...).expect(...). The panic means the filesystem write failed: the config directory does not exist, is not writable, or an OS-level I/O error occurred. Because expect() is used instead of error propagation, the whole application thread panics on failure.","triggerScenarios":"Calling save_changes after changing settings when CONFIG_DIR was deleted or never created, the disk is full, the path is read-only, or the user lacks write permission on the config file/directory.","commonSituations":"Users running the app from a read-only mount or with a relocated/locked HOME dir; permission changes on ~/.config; full disk after a large download; sandboxed/flatpak environments where CONFIG_DIR points outside the allowed sandbox.","solutions":["Ensure the config directory exists before writing (fs::create_dir_all on CONFIG_DIR's parent) in setup/startup code","Check permissions on the config file and its directory (ls -l; chown/chmod so the running user can write)","Free disk space or fix the underlying I/O error reported by the OS","Replace expect() with proper error handling so a failed save shows a message instead of panicking"],"exampleFix":"// before\nfs::write(&*CONFIG_FILE, toml).expect(\"Could not write config file to disk!\");\n// after\nif let Some(parent) = CONFIG_FILE.parent() { let _ = fs::create_dir_all(parent); }\nif let Err(e) = fs::write(&*CONFIG_FILE, toml) {\n    error!(\"Could not write config file to disk: {}\", e);\n}","handlingStrategy":"try-catch","validationCode":"// Rust caller-side check before triggering a settings save\nfn config_writable(file: &std::path::Path) -> bool {\n    if let Some(parent) = file.parent() {\n        if !parent.exists() && std::fs::create_dir_all(parent).is_err() { return false; }\n    }\n    match std::fs::OpenOptions::new().write(true).create(true).open(file) {\n        Ok(_) => true,\n        Err(e) => { eprintln!(\"config not writable: {}\", e); false }\n    }\n}","typeGuard":"fn config_file_writable(file: &std::path::Path) -> bool {\n    std::fs::metadata(file)\n        .map(|m| !m.permissions().readonly())\n        .unwrap_or(false)\n        && file.parent().map(|p| p.exists()).unwrap_or(false)\n}","tryCatchPattern":"// Rust: catch_unwind around the panicking API, or prefer upstream fix\nlet result = std::panic::catch_unwind(|| Config::save_changes(&settings, &device_id));\nmatch result {\n    Ok(_) => println!(\"saved\"),\n    Err(_) => eprintln!(\"Could not write config file to disk! Check permissions/disk.\"),\n}","preventionTips":["Create the config directory at app startup before any save","Run the app with write access to its config directory","Monitor disk space on the config volume","Prefer Result-returning file APIs over expect() in library code"],"tags":["rust","filesystem","config","panic"],"backgroundTag":"config-file-write-failed","analyzedSha":"11f27c671cba278d71296cdef4c5a5dba06add5e","analyzedAt":"2026-09-02T16:12:43.433Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T21:17:11.164Z"}