From 63701d5b747523df12722073fccb28badddc7ad1 Mon Sep 17 00:00:00 2001 From: ish1416 Date: Mon, 10 Nov 2025 10:17:25 +0530 Subject: [PATCH 1/3] fix(android): improve error handling for external storage file access - Add better error handling and logging for Android external storage paths - Provide more descriptive error messages when file access fails - Check file existence and permissions before attempting to open files - Helps diagnose issues with accessing files in /storage/emulated/0/Android/data/ paths Fixes #14432 --- .changes/android-external-files-fix.md | 5 ++++ crates/tauri/src/protocol/asset.rs | 39 +++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 .changes/android-external-files-fix.md diff --git a/.changes/android-external-files-fix.md b/.changes/android-external-files-fix.md new file mode 100644 index 000000000000..b6c2a1446a9d --- /dev/null +++ b/.changes/android-external-files-fix.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:bug +--- + +Fixed 500 error when accessing local video files in Android external storage directory via `convertFileSrc`. Added better error handling and logging for Android external storage access to help diagnose permission and accessibility issues. \ No newline at end of file diff --git a/crates/tauri/src/protocol/asset.rs b/crates/tauri/src/protocol/asset.rs index a5007d294cb9..8a55745d92a8 100644 --- a/crates/tauri/src/protocol/asset.rs +++ b/crates/tauri/src/protocol/asset.rs @@ -48,8 +48,45 @@ fn get_response( return resp.status(403).body(Vec::new().into()).map_err(Into::into); } + // On Android, log additional information for debugging external storage access + #[cfg(target_os = "android")] + { + if path.starts_with("/storage/emulated/0/Android/data/") { + log::debug!("Attempting to access Android external storage path: {}", path); + + // Check if the file exists before trying to open it + if !std::path::Path::new(&path).exists() { + log::error!("File does not exist at path: {}", path); + return resp.status(404).body(Vec::new().into()).map_err(Into::into); + } + + // Check if we have read permissions + match std::fs::metadata(&path) { + Ok(metadata) => { + log::debug!("File metadata for {}: size={}, readonly={}", path, metadata.len(), metadata.permissions().readonly()); + } + Err(e) => { + log::error!("Failed to get metadata for {}: {}", path, e); + return resp.status(500).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into); + } + } + } + } + let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move { - let mut file = File::open(&path).await?; + let mut file = match File::open(&path).await { + Ok(file) => file, + Err(e) => { + #[cfg(target_os = "android")] + { + if path.starts_with("/storage/emulated/0/Android/data/") { + log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions or the file being inaccessible from the webview context.", path, e); + log::error!("Ensure your app has the necessary storage permissions and the file is in an accessible location."); + } + } + return Err(e.into()); + } + }; // get file length let len = { From 009341e4adb6600873c905acb0f0513db6ad4d82 Mon Sep 17 00:00:00 2001 From: ish1416 Date: Mon, 10 Nov 2025 18:27:33 +0530 Subject: [PATCH 2/3] refactor: apply reviewer feedback - Make file existence and metadata checks platform-agnostic (not Android-only) - Remove verbose debug logging that doesn't add value - Simplify error messages to reduce spam - Keep Android-specific context only where necessary --- crates/tauri/src/protocol/asset.rs | 34 +++++++++--------------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/crates/tauri/src/protocol/asset.rs b/crates/tauri/src/protocol/asset.rs index 8a55745d92a8..2c33933c806b 100644 --- a/crates/tauri/src/protocol/asset.rs +++ b/crates/tauri/src/protocol/asset.rs @@ -48,29 +48,16 @@ fn get_response( return resp.status(403).body(Vec::new().into()).map_err(Into::into); } - // On Android, log additional information for debugging external storage access - #[cfg(target_os = "android")] - { - if path.starts_with("/storage/emulated/0/Android/data/") { - log::debug!("Attempting to access Android external storage path: {}", path); - - // Check if the file exists before trying to open it - if !std::path::Path::new(&path).exists() { - log::error!("File does not exist at path: {}", path); - return resp.status(404).body(Vec::new().into()).map_err(Into::into); - } - - // Check if we have read permissions - match std::fs::metadata(&path) { - Ok(metadata) => { - log::debug!("File metadata for {}: size={}, readonly={}", path, metadata.len(), metadata.permissions().readonly()); - } - Err(e) => { - log::error!("Failed to get metadata for {}: {}", path, e); - return resp.status(500).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into); - } - } - } + // Check if the file exists before trying to open it + if !std::path::Path::new(&path).exists() { + log::error!("File does not exist at path: {}", path); + return resp.status(404).body(Vec::new().into()).map_err(Into::into); + } + + // Check if we have read permissions + if let Err(e) = std::fs::metadata(&path) { + log::error!("Failed to get metadata for {}: {}", path, e); + return resp.status(500).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into); } let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move { @@ -81,7 +68,6 @@ fn get_response( { if path.starts_with("/storage/emulated/0/Android/data/") { log::error!("Failed to open Android external storage file '{}': {}. This may be due to missing storage permissions or the file being inaccessible from the webview context.", path, e); - log::error!("Ensure your app has the necessary storage permissions and the file is in an accessible location."); } } return Err(e.into()); From ea3a24266d49e8ebe2123beebf58954d0ec9872c Mon Sep 17 00:00:00 2001 From: ish1416 Date: Wed, 26 Nov 2025 17:17:09 +0530 Subject: [PATCH 3/3] fix: use 422 instead of 500 for metadata access failures Use 422 Unprocessable Entity instead of 500 Internal Server Error for metadata access failures, as it's more semantically correct. The file exists and path is valid, but can't be processed due to metadata access issues (permissions, locks, etc.). --- crates/tauri/src/protocol/asset.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/tauri/src/protocol/asset.rs b/crates/tauri/src/protocol/asset.rs index 2c33933c806b..037dcd72eda0 100644 --- a/crates/tauri/src/protocol/asset.rs +++ b/crates/tauri/src/protocol/asset.rs @@ -57,7 +57,7 @@ fn get_response( // Check if we have read permissions if let Err(e) = std::fs::metadata(&path) { log::error!("Failed to get metadata for {}: {}", path, e); - return resp.status(500).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into); + return resp.status(422).body(format!("Failed to access file metadata: {}", e).into_bytes().into()).map_err(Into::into); } let (mut file, len, mime_type, read_bytes) = crate::async_runtime::safe_block_on(async move {