Zackriya-Solutions/meetily · error

Cannot read file: {}

Error message

Cannot read file: {}

What it means

validate_audio_file (import.rs:144) wraps the std::fs::metadata error encountered while reading the file's size after the extension gate passed. exists() said true but metadata() failed - the classic TOCTOU window (file vanished between the two syscalls) plus permission and special-file cases. The raw io::Error is embedded, so the suffix distinguishes NotFound, PermissionDenied, and friends.

Source

Thrown at frontend/src-tauri/src/audio/import.rs:144

    // Check extension
    let extension = path
        .extension()
        .and_then(|e| e.to_str())
        .map(|e| e.to_lowercase())
        .unwrap_or_default();

    if !AUDIO_EXTENSIONS.contains(&extension.as_str()) {
        return Err(anyhow!(
            "Unsupported format: .{}. Supported: {}",
            extension,
            AUDIO_EXTENSIONS.join(", ")
        ));
    }

    // Get file size
    let metadata = std::fs::metadata(path)
        .map_err(|e| anyhow!("Cannot read file: {}", e))?;
    let size_bytes = metadata.len();

    // Check file size limit
    if size_bytes > MAX_FILE_SIZE_BYTES {
        return Err(anyhow!(
            "File too large: {:.2}GB. Maximum supported size is {}GB",
            size_bytes as f64 / (1024.0 * 1024.0 * 1024.0),
            MAX_FILE_SIZE_BYTES / (1024 * 1024 * 1024)
        ));
    }

    // Get filename without extension for title
    let filename = path
        .file_stem()
        .and_then(|s| s.to_str())
        .unwrap_or("Imported Audio")
        .to_string();

View on GitHub (pinned to 0281737d87)

Solutions

  1. Read the io::Error kind in the message: NotFound - re-pick the file; PermissionDenied - fix ownership/ACLs or run outside the sandbox; other kinds - check mount health.
  2. On Windows, grant Read via file Properties > Security; on macOS, re-pick the file in the current session rather than reusing a stored path.
  3. Pause sync tools (or wait for placeholder hydration) before importing.
  4. Retry once after a short delay if the message ends in NotFound - sync tools often release files quickly.
  5. Long term: replace exists()+metadata() with a single metadata() call, mapping NotFound to the friendlier File-does-not-exist message.

Example fix

// before: two syscalls, file can vanish between them
if !path.exists() { return Err(anyhow!("File does not exist: {}", path.display())); }
let metadata = std::fs::metadata(path).map_err(|e| anyhow!("Cannot read file: {}", e))?;

// after: single syscall, classified errors
let metadata = match std::fs::metadata(path) {
    Ok(m) => m,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound =>
        return Err(anyhow!("File does not exist: {}", path.display())),
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied =>
        return Err(anyhow!("Permission denied reading: {}", path.display())),
    Err(e) => return Err(anyhow!("Cannot read file: {}", e)),
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Frontend: prove the folder is readable before invoking validation
import { readDir } from '@tauri-apps/plugin-fs';
try { await readDir(dirname(path)); } catch { throw new Error('folder unreadable'); }

Try / catch

// Rust: classify the io::Error kind for the user
let metadata = match std::fs::metadata(path) {
    Ok(m) => m,
    Err(e) if e.kind() == std::io::ErrorKind::NotFound =>
        return Err(anyhow!("File does not exist: {}", path.display())),
    Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied =>
        return Err(anyhow!("Permission denied: {}", path.display())),
    Err(e) => return Err(anyhow!("Cannot read file: {}", e)),
};

Prevention

When it happens

Trigger: File deleted or renamed between the exists() check and the metadata() call (sync tools, antivirus quarantine); no read permission (other-user ownership, Windows ACLs, macOS App Sandbox losing the picked path); a special file (/dev node); a network share that dropped; a Windows path exceeding MAX_PATH without long-path enablement.

Common situations: Importing from cloud-sync folders (OneDrive/Dropbox placeholder dehydration causes metadata races); corporate folder-redirection with strict ACLs; macOS sandboxed builds losing file access after restart (security-scoped bookmark expired); antivirus locking large media files during scan.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16). Data as JSON: /api/errors/2c922d3f4f2d77ad. Report an issue: GitHub.