jamiepine/voicebox · error · HTTPException
Capture not found
Error message
Capture not found
What it means
Returned as a 404 from GET /captures/{capture_id} when captures_service.get_capture returns a falsy value — no Capture row matches the id (or the service's response model validation produced None). The handler returns early before serializing. This is the canonical lookup-miss for a single capture.
Source
Thrown at backend/routes/captures.py:89
async def list_captures_endpoint(
limit: int = 50,
offset: int = 0,
db: Session = Depends(get_db),
):
if limit < 1 or limit > 200:
raise HTTPException(status_code=400, detail="limit must be between 1 and 200")
if offset < 0:
raise HTTPException(status_code=400, detail="offset must be >= 0")
items, total = captures_service.list_captures(db, limit=limit, offset=offset)
return models.CaptureListResponse(items=items, total=total)
@router.get("/captures/{capture_id}", response_model=models.CaptureResponse)
async def get_capture_endpoint(capture_id: str, db: Session = Depends(get_db)):
capture = captures_service.get_capture(capture_id, db)
if not capture:
raise HTTPException(status_code=404, detail="Capture not found")
return capture
@router.get("/captures/{capture_id}/audio")
async def get_capture_audio_endpoint(capture_id: str, db: Session = Depends(get_db)):
"""Stream the original capture audio file."""
row = db.query(DBCapture).filter(DBCapture.id == capture_id).first()
if not row:
raise HTTPException(status_code=404, detail="Capture not found")
audio_path = config.resolve_storage_path(row.audio_path)
if audio_path is None or not audio_path.exists():
raise HTTPException(status_code=404, detail="Audio file not found")
return FileResponse(
audio_path,
media_type="audio/wav",
filename=f"capture_{capture_id}.wav",View on GitHub (pinned to 51f49dea19)
Solutions
- Confirm capture_id against the current captures list.
- Query the DB directly: SELECT * FROM captures WHERE id = ?.
- If the capture was deleted, remove the stale reference from the client.
- If expecting a just-created capture, retry briefly to account for commit/replication lag.
Defensive patterns
Strategy: validation
Validate before calling
const list = await listCaptures();
if (!list.items.some(c => c.id === captureId)) {
throw new Error('Capture id not in current list');
} Type guard
function captureExists(id: string, items: { id: string }[]): boolean {
return items.some(c => c.id === id);
} Try / catch
try {
const r = await fetch(`/captures/${id}`);
if (r.status === 404) { dropStaleCapture(id); return; }
} catch (e) { showNetworkError(e); } Prevention
- Source capture ids from the live list, not cached state.
- Remove deleted captures from the client immediately.
- For just-created captures, retry briefly to cover commit lag.
When it happens
Trigger: GET /captures/{capture_id} with an id that does not exist: deleted capture, typo, id from another deployment, or a just-created id not yet committed/visible.
Common situations: Client holds a capture id from a previous session after the capture was deleted; race where the client polls an id before the creating transaction committed; cross-environment id leakage (staging id sent to prod).
Related errors
- Audio file not found
- Generation failed; no audio available
- Sample not found
- Uploaded file is empty
- {exception message from wrapped ValueError}
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/61428a8c7e86478f.
Report an issue: GitHub.