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.

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)

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.