jamiepine/voicebox · warning · HTTPException

Sample not found

Error message

Sample not found

What it means

DELETE /profiles/samples/{sample_id} calls profiles.delete_profile_sample; if it returns falsy the route raises 404 'Sample not found'. The id did not match a sample row, or the row was already deleted. Note this route is keyed on sample_id alone (no profile_id in the path), so the 4040 cannot tell you whether the parent profile exists.

Solutions

  1. Treat the 404 as success for idempotent delete workflows.
  2. Refresh the sample list via GET /profiles/{profile_id}/samples to confirm whether the id still exists.
  3. Disable the delete control client-side after the first click to prevent double-submit.
Defensive patterns

Strategy: try-catch

Try / catch

resp = await client.delete(f"/profiles/samples/{sample_id}")
if resp.status_code == 404:
    # Already gone -- acceptable for idempotent delete
    pass
else:
    resp.raise_for_status()
remove_from_ui(sample_id)

Prevention

When it happens

Trigger: DELETE on a sample_id already removed; a typo in the id; a stale UI list referencing a sample deleted by another session; deleting a sample whose row was cleaned up by a storage-reconciliation job.

Common situations: Double-click delete; client cache out of sync; re-running a deletion script after it already succeeded.

Related errors


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

Appendix: source

Thrown at backend/routes/profiles.py:211

@router.get("/profiles/{profile_id}/samples", response_model=list[models.ProfileSampleResponse])
async def get_profile_samples(
    profile_id: str,
    db: Session = Depends(get_db),
):
    """Get all samples for a profile."""
    return await profiles.get_profile_samples(profile_id, db)


@router.delete("/profiles/samples/{sample_id}")
async def delete_profile_sample(
    sample_id: str,
    db: Session = Depends(get_db),
):
    """Delete a profile sample."""
    success = await profiles.delete_profile_sample(sample_id, db)
    if not success:
        raise HTTPException(status_code=404, detail="Sample not found")
    return {"message": "Sample deleted successfully"}


@router.put("/profiles/samples/{sample_id}", response_model=models.ProfileSampleResponse)
async def update_profile_sample(
    sample_id: str,
    data: models.ProfileSampleUpdate,
    db: Session = Depends(get_db),
):
    """Update a profile sample's reference text."""
    sample = await profiles.update_profile_sample(sample_id, data.reference_text, db)
    if not sample:
        raise HTTPException(status_code=404, detail="Sample not found")
    return sample


@router.post("/profiles/{profile_id}/avatar", response_model=models.VoiceProfileResponse)
async def upload_profile_avatar(

View on GitHub (pinned to 51f49dea19)