{"record":{"id":"0d1d5f4e0cf5c5f7","repo":"libnyanpasu/clash-nyanpasu","slug":"data-directory-not-found","errorCode":null,"errorMessage":"data directory not found.","messagePattern":"data directory not found\\.","errorType":"exception","errorClass":"std::io::Error (NotFound)","httpStatus":null,"severity":"error","filePath":"backend/tauri-plugin-deep-link/src/linux.rs","lineNumber":16,"sourceCode":"use std::{\n    fs::{create_dir_all, remove_file, File},\n    io::{Error, ErrorKind, Read, Result, Write},\n    os::unix::net::{UnixListener, UnixStream},\n    process::Command,\n};\n\nuse dirs::data_dir;\n\nuse crate::ID;\n\npub fn register<F: FnMut(String) + Send + 'static>(schemes: &[&str], handler: F) -> Result<()> {\n    listen(handler)?;\n\n    let mut target = data_dir()\n        .ok_or_else(|| Error::new(ErrorKind::NotFound, \"data directory not found.\"))?\n        .join(\"applications\");\n\n    create_dir_all(&target)?;\n\n    let exe = tauri_utils::platform::current_exe()?;\n\n    let file_name = format!(\n        \"{}-handler.desktop\",\n        exe.file_name()\n            .ok_or_else(|| Error::new(\n                ErrorKind::NotFound,\n                \"Couldn't get file name of curent executable.\",\n            ))?\n            .to_string_lossy()\n    );\n\n    target.push(&file_name);\n","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri-plugin-deep-link/src/linux.rs#L1-L34","documentation":"The Linux deep-link plugin register() writes a .desktop file under the XDG data dir's `applications` folder so the OS can route deep-link schemes to the app. It first resolves data_dir(); when no XDG data directory can be determined (typically $XDG_DATA_HOME unset and $HOME unavailable), it fails with this std::io::Error NotFound.","triggerScenarios":"Calling register() on Linux when both XDG_DATA_HOME and HOME are unset/empty — e.g. running the app from a systemd unit, cron, Docker container, or SSH session without a proper environment.","commonSituations":"App launched by a daemon/systemd service lacking the user environment; Flatpak/Snap sandbox restrictions; containers running as root with HOME unset; headless servers registering deep links.","solutions":["Set XDG_DATA_HOME (or HOME) in the launching environment, e.g. Environment=HOME=%h in the systemd unit","If running in a container/sandbox, mount or export a writable data dir before calling register","Only call register() in user-facing sessions (desktop entry) where XDG dirs are guaranteed","Wrap register() and degrade gracefully when data_dir() is None — deep-link registration is optional"],"exampleFix":"// before\nlet mut target = data_dir()\n    .ok_or_else(|| Error::new(ErrorKind::NotFound, \"data directory not found.\"))?\n    .join(\"applications\");\n// after\nlet Some(dir) = data_dir() else {\n    log::warn!(\"XDG data dir unavailable; skipping deep-link registration\");\n    return Ok(());\n};\nlet mut target = dir.join(\"applications\");","handlingStrategy":"validation","validationCode":"// before registering deep links on Linux\nlet has_data_dir = std::env::var(\"XDG_DATA_HOME\").map(|v| !v.is_empty())\n    .unwrap_or(false)\n    || std::env::var(\"HOME\").map(|v| !v.is_empty()).unwrap_or(false);\nif !has_data_dir {\n    log::warn!(\"XDG_DATA_HOME/HOME unset; skipping deep-link registration\");\n    return;\n}","typeGuard":"fn xdg_data_dir_available() -> bool {\n    dirs::data_dir().is_some()\n}","tryCatchPattern":"match deep_link::register(&schemes, handler) {\n    Err(e) if e.to_string().contains(\"data directory not found\") => {\n        log::warn!(\"no XDG data dir; deep links unregistered: {e}\");\n    }\n    Err(e) => return Err(e.into()),\n    Ok(()) => {}\n}","preventionTips":["Set XDG_DATA_HOME or HOME in service/daemon/container launch environments","Register deep links only inside real desktop sessions","Make deep-link registration optional with graceful degradation"],"tags":["linux","xdg","deep-link"],"backgroundTag":"missing-env-var","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}