tonhowtf/omniget · error
Failed to read .torrent file
Error message
Failed to read .torrent file: {} What it means
When the download `url` is not a magnet URI, download treats it as a path to a .torrent file. It checks that the path exists and has extension ".torrent", then reads the bytes with tokio::fs::read; any I/O error during that read is wrapped in this error with the OS reason. The file passed the exists/extension check but could not actually be read.
Solutions
- Read the wrapped `{}` OS error — permission denied vs not-found dictates the fix.
- Verify the .torrent file still exists and is readable by the app user (ls -l / icacls).
- Confirm the path is a regular file, not a directory, and is on a mounted, available volume.
- Handle the error in the caller by prompting the user to re-select the .torrent file.
- Prefer opening the file once (File::open) and reporting an explicit 'file missing' error instead of relying on the exists() check.
Example fix
// before
let bytes = tokio::fs::read(path).await
.map_err(|e| anyhow::anyhow!("Failed to read .torrent file: {}", e))?;
// after
let bytes = tokio::fs::read(path).await.map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
anyhow::anyhow!("Torrent file no longer exists: {}", path.display())
} else {
anyhow::anyhow!("Failed to read .torrent file: {}", e)
}
})?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate the torrent path before calling download
fn validate_torrent_path(path: &str) -> Result<(), String> {
let p = std::path::Path::new(path);
if !p.is_file() { return Err(format!("not a regular file: {}", path)); }
if p.extension().map(|e| e != "torrent").unwrap_or(true) { return Err("extension is not .torrent".into()); }
std::fs::File::open(p).map(|_| ()).map_err(|e| format!("unreadable: {}", e))
} Try / catch
match download(path, opts).await {
Err(e) if e.to_string().contains("Failed to read .torrent file") => {
// file vanished or unreadable; prompt user to re-select the .torrent
ui.prompt_reselect_torrent(path);
Err(e)
}
other => other,
} Prevention
- Verify the .torrent file exists and is readable right before adding it to the queue
- Don't move or delete .torrent files while a download is pending
- Keep .torrent files on a local, always-mounted volume rather than network/removable drives
- Check file permissions for the user account running the app
When it happens
Trigger: Calling download with a local .torrent path where tokio::fs::read fails — permission denied, file deleted between the exists() check and the read, path is a directory named x.torrent, or an IO error on a network/removable drive.
Common situations: File moved/deleted after being added to the UI (TOCTOU between exists() and read()); downloading on a machine where the .torrent lives on an unavailable drive; restrictive ACLs; passing a directory or a file without read permission.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to read .torrent file
- nao leu
- Failed to move into place
- Failed to replace
- Write error (disk full?)
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/af7739583ad66350.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/platforms/magnet.rs:178
*dir_guard = Some(output_dir.clone());
s
} else {
tracing::info!("[magnet] reusing existing session");
guard.as_ref().unwrap().clone()
}
};
let add_torrent = if url.starts_with("magnet:")
|| url.starts_with("http://")
|| url.starts_with("https://")
{
AddTorrent::from_url(url)
} else {
let path = std::path::Path::new(url);
if path.exists() && path.extension().map(|e| e == "torrent").unwrap_or(false) {
let bytes = tokio::fs::read(path)
.await
.map_err(|e| anyhow::anyhow!("Failed to read .torrent file: {}", e))?;
AddTorrent::from_bytes(bytes)
} else {
AddTorrent::from_url(url)
}
};
let only_files = opts
.torrent_files
.as_ref()
.filter(|v| !v.is_empty())
.cloned();
if let Some(sel) = &only_files {
tracing::info!("[magnet] selective download: {} file(s)", sel.len());
}
let trackers = if opts.torrent_auto_trackers {
let list = crate::core::trackers::extra_trackers();
tracing::info!("[magnet] injecting {} public trackers", list.len());
Some(list)
} else {View on GitHub (pinned to 8600b91f42)