jamiepine/voicebox · warning · HTTPException

ROCm backend download already in progress

Error message

ROCm backend download already in progress

What it means

Returned by POST /backend/download-rocm when an existing progress entry for rocm.PROGRESS_KEY already has status 'downloading' or 'extracting' (HTTP 409). The handler reads progress_manager.get_progress and treats any in-flight state as a conflict, preventing concurrent downloads. It is a deliberate guard, not a transient failure.

Source

Thrown at backend/routes/rocm.py:32


@router.get("/backend/rocm-status")
async def get_rocm_status():
    """Get ROCm backend download/availability status."""
    from ..services import rocm

    return rocm.get_rocm_status()


@router.post("/backend/download-rocm")
async def download_rocm_backend():
    """Download the ROCm backend binary."""
    from ..services import rocm

    progress_manager = get_progress_manager()
    existing = progress_manager.get_progress(rocm.PROGRESS_KEY)
    if existing and existing.get("status") in {"downloading", "extracting"}:
        raise HTTPException(status_code=409, detail="ROCm backend download already in progress")

    async def _download():
        try:
            await rocm.download_rocm_binary()
        except Exception as e:
            logger.error("ROCm download failed: %s", e)

    create_background_task(_download())
    return {"message": "ROCm backend download started", "progress_key": rocm.PROGRESS_KEY}


@router.delete("/backend/rocm")
async def delete_rocm_backend():
    """Delete the downloaded ROCm backend binary."""
    from ..services import rocm

    if rocm.is_rocm_active():
        raise HTTPException(

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Poll GET /backend/rocm-progress (SSE) to observe the existing download's status before re-issuing POST.
  2. If the status is genuinely stuck ('downloading' indefinitely after a crash), reset the progress entry via the service or restart the backend, then retry.
  3. Disable the download button in the UI while status is downloading/extracting.
  4. Treat 409 as 'already started, subscribe to progress' rather than an error to retry.

Example fix

// before
await api.post('/backend/download-rocm');

// after
const status = await getRocmStatus();
if (status === 'downloading' || status === 'extracting') {
  return subscribeToProgress();
}
await api.post('/backend/download-rocm');
Defensive patterns

Strategy: retry

Validate before calling

async function rocmDownloadActive() {
  const s = await (await fetch('/api/backend/rocm-status')).json();
  return s.status === 'downloading' || s.status === 'extracting';
}

Type guard

function isRocmInProgress(s) { return s && (s.status === 'downloading' || s.status === 'extracting'); }

Try / catch

try { await api.post('/backend/download-rocm'); }
catch (e) {
  if (e.response?.status === 409) { await subscribeToProgress(); return; }
  throw e;
}

Prevention

When it happens

Trigger: Calling download-rocm while a previous download/extract is still running. A prior download task crashed without updating progress status away from 'downloading'/'extracting', leaving a stale in-flight entry.

Common situations: User double-clicks the download button. Frontend retries on a slow network without checking progress. Background task died (process restart) but progress status was never reset to failed/done.

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/5ac9a00f1b3d7bd8. Report an issue: GitHub.