Zackriya-Solutions/meetily · error
Source file not found
Error message
Source file not found: {} What it means
run_import (import.rs:323) re-checks Path::exists() on the source file at the start of the actual import, after start_import acquired the guard. This is a second, deeper existence check than validate_audio_file's - the file may have passed validation earlier (or validation was skipped) and then vanished before the copy stage. It fails fast before creating the meeting folder or copying anything.
Solutions
- Re-select the file with the picker and import immediately - closes the race in the common case.
- Validate-then-import in one user action; do not stage the path across long waits or app restarts.
- Check removable media is still mounted; copy large imports to local disk first if the source is a flaky network share.
- If it recurs with the file visibly present, compare the logged path.display() against the real path for Unicode normalization or trailing-space differences.
- Code-level: run validate_audio_file inside run_import too so both layers report the friendlier File-does-not-exist message consistently.
Example fix
// frontend: before - path stored from a previous session
await invoke('import_audio_file', { sourcePath: lastSession.path, ... });
// frontend: after - revalidate existence right before invoking
import { open } from '@tauri-apps/plugin-dialog';
const picked = await open({ multiple: false });
if (!picked) return;
await invoke('validate_audio_file', { path: picked }); // throws if gone
await invoke('import_audio_file', { sourcePath: picked, ... }); Defensive patterns
Strategy: validation
Validate before calling
// Frontend: existence check immediately before the import invoke
import { open } from '@tauri-apps/plugin-dialog';
const picked = await open({ multiple: false });
if (!picked) return;
await invoke('validate_audio_file', { path: picked }); // throws if the file vanished
await invoke('import_audio_file', { sourcePath: picked }); Try / catch
try { await invoke('import_audio_file', { sourcePath }); }
catch (e) {
if (String(e).includes('Source file not found')) promptRepickFile();
else throw e;
} Prevention
- Validate and import in one user action; never stage source paths across restarts.
- Keep removable media mounted through the whole import, or copy to local disk first.
- Re-pick files after long dialog-idle periods.
- Compare the logged path with the real one for Unicode/trailing-space differences.
When it happens
Trigger: The file passed the earlier validate call but was deleted/renamed in between (sync eviction, quarantine, user cleanup); the frontend invoked import_audio_file directly with a stale path persisted from a previous session, without validating first; the removable drive holding the file was ejected between selection and import; a download still in progress rotated the .part file.
Common situations: Users picking a file, leaving the dialog open a long time, then clicking Import after the file moved; cloud-sync placeholders dehydrated; re-using last session's path via stored state; antivirus quarantine removing the file post-scan.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Cannot read file
- File does not exist
- File too large: GB. Maximum supported size is GB
- Unsupported format: .
- Copy task join error
AI-assisted analysis of Zackriya-Solutions/meetily@a2cb62e827 (2026-08-16).
Data as JSON: /api/errors/59d21d2e3e6cefbe.
Report an issue: GitHub.
Appendix: source
Thrown at frontend/src-tauri/src/audio/import.rs:324
}
result
}
/// Internal function to run import
async fn run_import<R: Runtime>(
app: AppHandle<R>,
source_path: String,
title: String,
language: Option<String>,
model: Option<String>,
provider: Option<String>,
) -> Result<ImportResult> {
let source = PathBuf::from(&source_path);
// Validate source file
if !source.exists() {
return Err(anyhow!("Source file not found: {}", source.display()));
}
info!(
"Starting import for '{}' from {} with language {:?}, model {:?}, provider {:?}",
title, source_path, language, model, provider
);
// Determine which provider to use (default to whisper)
let use_parakeet = provider.as_deref() == Some("parakeet");
emit_progress(&app, "copying", 5, "Creating meeting folder...");
// Check for cancellation
if IMPORT_CANCELLED.load(Ordering::SeqCst) {
return Err(anyhow!("Import cancelled"));
}
// Create meeting folderView on GitHub (pinned to a2cb62e827)