Zackriya-Solutions/meetily · warning · anyhow::Error

Download already in progress for model

Error message

Download already in progress for model: {}

What it means

download_model checks the active_downloads set at entry and rejects a second concurrent download of the same model name. This prevents two HTTP streams writing the same ggml-<name>.bin path simultaneously. The first download continues unaffected; the duplicate call fails immediately.

Solutions

  1. Wait for the in-flight download — subscribe to its progress events until 100 or completion
  2. Disable the Download button while the model shows Downloading status
  3. If the flag is stale because a prior call hung, cancel the download or restart the app, then retry

Example fix

// before
button.onClick(() => invoke('download_model', { modelName })); // double-fire

// after
let downloading = false;
button.onClick(async () => {
  if (downloading) return;
  downloading = true;
  try { await invoke('download_model', { modelName }); }
  finally { downloading = false; }
});
Defensive patterns

Strategy: validation

Validate before calling

const models = await invoke<ModelInfo[]>('get_whisper_models');
const downloading = models.find(x => x.name === modelName)?.status === 'Downloading';
if (downloading) {
  // attach to the existing progress stream instead of starting a second one
  return;
}
await invoke('download_model', { modelName });

Type guard

const isDownloading = (m: ModelInfo | undefined): boolean => m?.status === 'Downloading';

Try / catch

try {
  await invoke('download_model', { modelName });
} catch (e) {
  if (String(e).includes('already in progress')) {
    // benign: join the existing download's progress events
  } else { throw e; }
}

Prevention

When it happens

Trigger: Double-clicking the Download button before it disables; two UI components both invoking download_model for the same name; automatic retry logic firing while the first attempt still streams.

Common situations: Missing debounce on the download button; background auto-download racing a user-initiated download; optimistic-refresh frontend that re-issues the call.

Related errors


AI-assisted analysis of Zackriya-Solutions/meetily@a2cb62e827 (2026-09-12). Data as JSON: /api/errors/93f8d7903733853b. Report an issue: GitHub.

Appendix: source

Thrown at frontend/src-tauri/src/whisper_engine/whisper_engine.rs:935

                {
                    let mut models = self.available_models.write().await;
                    if let Some(model) = models.get_mut(model_name) {
                        model.status = ModelStatus::Missing;
                    }
                }

                Ok(format!("Successfully deleted model '{}'", model_name))
            }
            _ => {
                Err(anyhow!("Can only delete corrupted or available models. Model '{}' has status: {:?}", model_name, model_info.status))
            }
        }
    }
    
    async fn reserve_active_download(&self, model_name: &str) -> Result<Arc<ActiveDownload>> {
        let mut active_downloads = self.active_downloads.lock().await;
        if active_downloads.contains_key(model_name) {
            return Err(anyhow!("Download already in progress for model: {}", model_name));
        }

        let (completion, _) = watch::channel(false);
        let active_download = Arc::new(ActiveDownload {
            cancellation: CancellationToken::new(),
            completion,
        });

        active_downloads.insert(model_name.to_string(), Arc::clone(&active_download));
        Ok(active_download)
    }

    async fn finish_download(
        &self,
        model_name: &str,
        active_download: &Arc<ActiveDownload>,
        file_path: &PathBuf,
        mut result: Result<()>,

View on GitHub (pinned to a2cb62e827)