{"record":{"id":"c30c33ae5ace8ccc","repo":"tonhowtf/omniget","slug":"failed-to-read-torrent-file-mod","errorCode":null,"errorMessage":"Failed to read .torrent file: {}","messagePattern":"Failed to read \\.torrent file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/magnet/mod.rs","lineNumber":178,"sourceCode":"                *dir_guard = Some(output_dir.clone());\n                s\n            } else {\n                tracing::info!(\"[magnet] reusing existing session\");\n                guard.as_ref().unwrap().clone()\n            }\n        };\n\n        let add_torrent = if url.starts_with(\"magnet:\")\n            || url.starts_with(\"http://\")\n            || url.starts_with(\"https://\")\n        {\n            AddTorrent::from_url(url)\n        } else {\n            let path = std::path::Path::new(url);\n            if path.exists() && path.extension().map(|e| e == \"torrent\").unwrap_or(false) {\n                let bytes = tokio::fs::read(path)\n                    .await\n                    .map_err(|e| anyhow::anyhow!(\"Failed to read .torrent file: {}\", e))?;\n                AddTorrent::from_bytes(bytes)\n            } else {\n                AddTorrent::from_url(url)\n            }\n        };\n        let only_files = opts\n            .torrent_files\n            .as_ref()\n            .filter(|v| !v.is_empty())\n            .cloned();\n        if let Some(sel) = &only_files {\n            tracing::info!(\"[magnet] selective download: {} file(s)\", sel.len());\n        }\n        let trackers = if opts.torrent_auto_trackers {\n            let list = crate::core::trackers::extra_trackers();\n            tracing::info!(\"[magnet] injecting {} public trackers\", list.len());\n            Some(list)\n        } else {","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/magnet/mod.rs#L160-L196","documentation":"Wraps a `tokio::fs::read` failure in `download` when the URL is actually a local path to a `.torrent` file. Before the read, the code checks `path.exists()` and the `.torrent` extension; the read itself then failed (I/O error), so the raw metainfo bytes could not be loaded for `AddTorrent::from_bytes`.","triggerScenarios":"Calling `download` with a local `.torrent` file path that passed the `exists()` check but failed to read: permission denied on the file, it's a directory named `x.torrent`, the file vanished between the exists-check and the read (TOCTOU), or a broken symlink.","commonSituations":"Torrent file moved/deleted after being picked in the UI; file on a disconnected network drive or unmounted volume; OS permission restrictions (e.g. macOS sandbox or Windows ACLs) blocking read; a folder misleadingly named `foo.torrent`.","solutions":["Read the wrapped `{}` IO error to distinguish permission-denied vs not-found vs is-a-directory","Re-check that the file still exists and is a regular readable file right before download; re-pick the .torrent file if it moved","Fix filesystem permissions (chmod/ACL) or run the app with access to the file's location","Pass a magnet URI instead of a file path if local file access is problematic"],"exampleFix":"// before\nlet bytes = tokio::fs::read(path).await\n    .map_err(|e| anyhow::anyhow!(\"Failed to read .torrent file: {}\", e))?;\n// after\nlet bytes = match tokio::fs::read(path).await {\n    Ok(b) => b,\n    Err(e) => {\n        tracing::warn!(\"cannot read torrent file {}: {e}; falling back to magnet URL\", path.display());\n        return Err(anyhow!(\"Torrent file unreadable: {e}. Re-select the .torrent file.\"));\n    }\n};","handlingStrategy":"validation","validationCode":"fn validate_torrent_file(path: &str) -> Result<(), String> {\n    let p = std::path::Path::new(path);\n    if !p.is_file() { return Err(format!(\"not a regular file: {path}\")); }\n    if p.extension().map(|e| e != \"torrent\").unwrap_or(true) { return Err(\"missing .torrent extension\".into()); }\n    std::fs::metadata(p).and_then(|m| m.permissions()).map_err(|e| e.to_string())?;\n    Ok(())\n}","typeGuard":"fn is_readable_torrent_path(url: &str) -> bool {\n    let p = std::path::Path::new(url);\n    p.is_file() && p.extension().map(|e| e == \"torrent\").unwrap_or(false)\n}","tryCatchPattern":"match downloader.download(&info, &opts, tx).await {\n    Err(e) if e.to_string().contains(\"Failed to read .torrent file\") => {\n        Err(anyhow!(\"The .torrent file could not be read ({e}). Re-select or re-download the file.\"))\n    }\n    other => other,\n}","preventionTips":["Re-check the file exists and is a regular file immediately before reading (avoid TOCTOU gaps)","Check file permissions/ownership, especially on sandboxed macOS or Windows ACL-restricted locations","Verify the file wasn't on an unmounted or disconnected volume at selection time","Prefer magnet URIs when local file access is unreliable"],"tags":["torrent","filesystem","io","file-read"],"backgroundTag":"file-read-failed","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"}