{"record":{"id":"c5af2d495074bdeb","repo":"jamiepine/voicebox","slug":"cuda-backend-already-downloaded","errorCode":null,"errorMessage":"CUDA backend already downloaded","messagePattern":"CUDA backend already downloaded","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"backend/routes/cuda.py","lineNumber":34,"sourceCode":"@router.get(\"/backend/cuda-status\")\nasync def get_cuda_status():\n    \"\"\"Get CUDA backend download/availability status.\"\"\"\n    from ..services import cuda\n\n    return cuda.get_cuda_status()\n\n\n@router.post(\"/backend/download-cuda\")\nasync def download_cuda_backend():\n    \"\"\"Download the CUDA backend binary.\"\"\"\n    from ..services import cuda\n\n    unsupported_reason = cuda.get_cuda_download_unsupported_reason()\n    if unsupported_reason:\n        raise HTTPException(status_code=409, detail=unsupported_reason)\n\n    if cuda.get_cuda_binary_path() is not None:\n        raise HTTPException(status_code=409, detail=\"CUDA backend already downloaded\")\n\n    progress_manager = get_progress_manager()\n    existing = progress_manager.get_progress(cuda.PROGRESS_KEY)\n    if existing and existing.get(\"status\") == \"downloading\":\n        raise HTTPException(status_code=409, detail=\"CUDA backend download already in progress\")\n\n    async def _download():\n        try:\n            await cuda.download_cuda_binary()\n        except Exception as e:\n            logger.error(\"CUDA download failed: %s\", e)\n\n    create_background_task(_download())\n    return {\"message\": \"CUDA backend download started\", \"progress_key\": \"cuda-backend\"}\n\n\n@router.delete(\"/backend/cuda\")\nasync def delete_cuda_backend():","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/cuda.py#L16-L52","documentation":"HTTP 409 raised by POST /backend/download-cuda when cuda.get_cuda_binary_path() returns a non-None path, meaning the CUDA executable already exists inside {data_dir}/backends/cuda/. The endpoint refuses to redownload because the backend is already present. To force a refresh you must delete it first (DELETE /backend/cuda) or rely on the auto-update path that checks version mismatches.","triggerScenarios":"Calling POST /backend/download-cuda after a previous successful download left the binary in place.","commonSituations":"Clicking download again to 'update'; a reinstall that did not clear the data directory; the auto-update task already populated the binary at startup.","solutions":["If you want a fresh copy, call DELETE /backend/cuda first (only when CUDA is not active).","To upgrade, rely on the startup auto-update (check_and_update_cuda_binary) which handles version mismatches.","Check GET /backend/cuda status.available before offering the download action."],"exampleFix":"// before\nawait fetch('/backend/download-cuda', { method: 'POST' });\n// after\nconst status = await fetch('/backend/cuda').then(r => r.json());\nif (status.available) { /* already installed */ return; }\nawait fetch('/backend/download-cuda', { method: 'POST' });","handlingStrategy":"validation","validationCode":"const status = await fetch('/backend/cuda').then(r => r.json());\nif (status.available) throw new Error('cuda backend already installed');","typeGuard":"function isCudaInstalled(s): s is { available: true } { return s?.available === true; }","tryCatchPattern":"const r = await fetch('/backend/download-cuda', { method:'POST' });\nif (r.status === 409) { const { detail } = await r.json(); /* already downloaded | in progress | unsupported */ }","preventionTips":["Check status.available before offering download.","Use DELETE (when inactive) + POST to force a refresh.","Rely on startup auto-update for version upgrades."],"tags":["cuda","http","conflict","state","fastapi"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}