{"record":{"id":"1f4e5a368449ed7f","repo":"tonhowtf/omniget","slug":"sem-pasta-de-dados","errorCode":null,"errorMessage":"sem pasta de dados","messagePattern":"sem pasta de dados","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/tools/ai_keys.rs","lineNumber":221,"sourceCode":"}\n\n// ── Armazenamento ──────────────────────────────────────────────────────\n\nstatic LOCK: Mutex<()> = Mutex::new(());\n\nfn file() -> Option<std::path::PathBuf> {\n    super::tools_dir().map(|d| d.join(\"ai-keys.json\"))\n}\n\nfn load() -> Vec<KeyEntry> {\n    file()\n        .and_then(|p| std::fs::read_to_string(p).ok())\n        .and_then(|s| serde_json::from_str(&s).ok())\n        .unwrap_or_default()\n}\n\nfn save(list: &[KeyEntry]) -> anyhow::Result<()> {\n    let p = file().ok_or_else(|| anyhow!(\"sem pasta de dados\"))?;\n    std::fs::create_dir_all(p.parent().unwrap())?;\n    let tmp = p.with_extension(\"json.tmp\");\n    std::fs::write(&tmp, serde_json::to_string_pretty(list)?)?;\n    std::fs::rename(&tmp, &p)?;\n    Ok(())\n}\n\npub fn list() -> Vec<KeyView> {\n    let _g = LOCK.lock().unwrap_or_else(|e| e.into_inner());\n    load().iter().map(KeyEntry::view).collect()\n}\n\n/// Entrada completa (com segredo) para uso interno do app.\npub fn entry_with_secret(id: &str) -> anyhow::Result<KeyEntry> {\n    get(id)\n}\n\nfn get(id: &str) -> anyhow::Result<KeyEntry> {","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/tools/ai_keys.rs#L203-L239","documentation":"ai_keys::save persists the AI key list to a JSON file whose path comes from file() (ai_keys.rs:209); when the base data directory cannot be resolved, file() returns None and save fails with \"sem pasta de dados\" (\"no data folder\"). All writers (update, upsert, delete) funnel through save, so they all fail.","triggerScenarios":"Any key mutation (update/upsert/delete) on a system where the directories provider cannot resolve the config/data dir — e.g. $HOME unset or invalid XDG env vars.","commonSituations":"Headless/test environments without a user profile; XDG_CONFIG_HOME set to a relative path; running the app under a service account.","solutions":["Run with a proper user session ($HOME set, writable config dir)","Fix invalid XDG_CONFIG_HOME/XDG_DATA_HOME environment variables","Pre-check file().is_some() before offering key-management features and degrade gracefully","Add a fallback path when file() returns None"],"exampleFix":"// before\nlet p = file().ok_or_else(|| anyhow!(\"sem pasta de dados\"))?;\n// after\nlet p = file().or_else(|| std::env::var_os(\"HOME\").map(|h| PathBuf::from(h).join(\".config/omniget/ai_keys.json\")))\n    .ok_or_else(|| anyhow!(\"sem pasta de dados\"))?;","handlingStrategy":"fallback","validationCode":"fn can_persist_keys() -> bool { file().is_some() && file().unwrap().parent().map(|p| p.exists() || std::fs::create_dir_all(p).is_ok()).unwrap_or(false) }","typeGuard":null,"tryCatchPattern":"match upsert_key(entry).await {\n    Err(e) if e.to_string() == \"sem pasta de dados\" => disable_key_ui_and_show_setup_hint(),\n    other => handle(other),\n}","preventionTips":["Check that a writable config dir exists at app startup","Avoid running the app under accounts without $HOME","Provide an explicit override path setting for the keys file"],"tags":["filesystem","environment","config"],"backgroundTag":"missing-config-file","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}