Zackriya-Solutions/meetily · warning
Import already in progress
Error message
Import already in progress
What it means
start_import (import.rs:263) tries to acquire the ImportGuard via compare_exchange on the global IMPORT_IN_PROGRESS AtomicBool and loses the race - another import is currently running in this process. The guard is a deliberate single-flight mechanism (RAII Drop clears the flag, so even a panic cannot leave it stuck) preventing two imports from writing meetings/transcripts concurrently and contending for the whisper/parakeet engines.
Source
Thrown at frontend/src-tauri/src/audio/import.rs:263
debug!(
"Extracted metadata: {}Hz, {} frames, {:.2}s",
sample_rate, n_frames, duration_seconds
);
Ok(duration_seconds)
}
/// Start import of an audio file
pub async fn start_import<R: Runtime>(
app: AppHandle<R>,
source_path: String,
title: String,
language: Option<String>,
model: Option<String>,
provider: Option<String>,
) -> Result<ImportResult> {
// Acquire guard - ensures flag is cleared even on panic/early return
let _guard = ImportGuard::acquire().map_err(|e| anyhow!(e))?;
// Reset cancellation flag
IMPORT_CANCELLED.store(false, Ordering::SeqCst);
let use_parakeet = provider.as_deref() == Some("parakeet");
let result = run_import(
app.clone(),
source_path,
title,
language,
model,
provider,
)
.await;
// Unload the engine after the batch job (success, failure, or cancellation)
super::common::unload_engine_after_batch(use_parakeet).await;
View on GitHub (pinned to 0281737d87)
Solutions
- Retry after the current import completes - the error is transient by design; subscribe to the import progress events to know when it is safe.
- Make the frontend idempotent: disable the Import button synchronously on click and re-enable only on the terminal import-completed/import-error event.
- If the UI believes nothing is running but the error persists, an import may still be finishing; wait for its event or restart the app (Drop guarantees the flag clears when the task ends).
- For programmatic callers: await the first invocation's future before starting a second; never fire-and-forget import invokes.
- Check app logs: 'Starting import for ...' lines show which import currently holds the guard.
Example fix
// frontend: before - button stays enabled, double-click double-invokes
const onImport = () => invoke('import_audio_file', payload);
// frontend: after - single-flight guard keyed to the running request
const importingRef = useRef(false);
const onImport = async () => {
if (importingRef.current) return;
importingRef.current = true;
try { await invoke('import_audio_file', payload); }
finally { importingRef.current = false; }
}; Defensive patterns
Strategy: validation
Validate before calling
// Frontend: single-flight guard so the second invoke never happens
const importingRef = useRef(false);
async function importFile(payload) {
if (importingRef.current) { setStatus('busy'); return; }
importingRef.current = true;
try { return await invoke('import_audio_file', payload); }
finally { importingRef.current = false; }
} Try / catch
// Treat as transient: wait for the running import's terminal event, then retry once
try { await invoke('import_audio_file', payload); }
catch (e) {
if (String(e).includes('Import already in progress')) {
await waitForEvent('import-completed', 'import-error');
return invoke('import_audio_file', payload); // single retry after drain
}
throw e;
} Prevention
- Disable the Import button synchronously on click; re-enable only on terminal import events.
- Never fire-and-forget import invokes; always await.
- In React, guard effects that auto-start imports with a ref/flag to survive StrictMode double-mounts.
- Subscribe to import progress events so the UI always knows an import is running.
When it happens
Trigger: Double-clicking Import before the first click's async invoke disabled the button; frontend state desync - the button re-enabled after a transient render while the backend import still runs; invoking import_audio_file twice in quick succession (retry logic that does not await the first call); hot-reload re-mounting a component whose effect fires the import again.
Common situations: Janky UI where the disable-button effect lags the invoke; users spamming the button on slow disks; dev hot-reload double-firing effects; automated tests invoking import in parallel.
Related errors
- Update check already in progress
- Invalid input path (non-UTF8)
- Invalid temp path (non-UTF8)
- No audio samples decoded from file
- File does not exist: {}
AI-assisted analysis of Zackriya-Solutions/meetily@0281737d87 (2026-08-16).
Data as JSON: /api/errors/9728a0009e3f1de7.
Report an issue: GitHub.