{"record":{"id":"e684e2f3e14bca62","repo":"tonhowtf/omniget","slug":"path-is-not-a-file-mod","errorCode":null,"errorMessage":"Path is not a file: {}","messagePattern":"Path is not a file: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/platforms/p2p/mod.rs","lineNumber":221,"sourceCode":"    pub file_name: String,\n    pub file_size: u64,\n    pub cancel_token: CancellationToken,\n    pub progress: Arc<tokio::sync::Mutex<f64>>,\n    pub status: Arc<tokio::sync::Mutex<String>>,\n    pub sent_bytes: Arc<tokio::sync::Mutex<u64>>,\n    pub paused: Arc<std::sync::atomic::AtomicBool>,\n}\n\npub async fn start_send(\n    file_path: PathBuf,\n    cancel_token: CancellationToken,\n) -> anyhow::Result<P2pSendSession> {\n    let metadata = tokio::fs::metadata(&file_path)\n        .await\n        .map_err(|e| anyhow!(\"File not found: {}\", e))?;\n\n    if !metadata.is_file() {\n        anyhow::bail!(\"Path is not a file: {}\", file_path.display());\n    }\n\n    let file_size = metadata.len();\n    let file_name = file_path\n        .file_name()\n        .map(|n| n.to_string_lossy().to_string())\n        .unwrap_or_else(|| \"file\".to_string());\n\n    let code = words::generate_code();\n\n    tracing::info!(\"[p2p] share code generated: {}\", code);\n\n    Ok(P2pSendSession {\n        code,\n        file_path,\n        file_name,\n        file_size,\n        cancel_token,","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/src/platforms/p2p/mod.rs#L203-L239","documentation":"start_send() first calls tokio::fs::metadata on the given path; if the metadata succeeds but is_file() is false, the path is a directory/symlink-to-dir/device, and start_send bails with this message. The library only transfers regular files.","triggerScenarios":"Calling start_send with a directory path, a special file (/dev/*, named pipe), or a path that exists but is not a regular file.","commonSituations":"User drags a folder into the send UI, a symlink points to a directory, or a path built from string concatenation accidentally resolves to a directory.","solutions":["Validate the path is a regular file before calling start_send (fs::metadata(path)?.is_file()).","If a directory was intended, enumerate its files and send them individually or as an archive.","Resolve symlinks with tokio::fs::canonicalize first so the check reflects the target's type.","Improve the UI to reject folders at selection time."],"exampleFix":"// before\nstart_send(dir_path.into()).await?;\n// after\nlet md = tokio::fs::metadata(&path).await?;\nif !md.is_file() {\n    anyhow::bail!(\"Please select a regular file, not a directory: {}\", path.display());\n}\nstart_send(path).await?;","handlingStrategy":"validation","validationCode":"let md = tokio::fs::metadata(&path).await?;\nanyhow::ensure!(md.is_file(), \"{} is not a regular file\", path.display());","typeGuard":"fn is_regular_file(path: &std::path::Path) -> bool {\n    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)\n}","tryCatchPattern":"if let Err(e) = start_send(path.clone()).await {\n    if e.to_string().contains(\"Path is not a file\") {\n        ui.show_warning(\"Select a file, not a folder\");\n    } else { return Err(e); }\n}","preventionTips":["Use a file picker (not a free-text path field) so users can't select directories.","Canonicalize paths before validation to resolve symlinks.","Validate is_file() in the UI layer before invoking the Tauri command.","Special-case folders: offer to zip/enumerate instead of failing."],"tags":["filesystem","validation","p2p","path"],"backgroundTag":"invalid-argument-value","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"}