jamiepine/voicebox · info · HTTPException
No avatar found for this profile
Error message
No avatar found for this profile
What it means
GET /profiles/{profile_id}/avatar reaches this branch only when the profile exists but profile.avatar_path is falsy (None/empty). The route raises 404 'No avatar found for this profile'. This is distinct from 'Profile not found' (id missing) and 'Avatar file not found' (avatar_path set but file gone): here the profile simply never had an avatar uploaded, or it was previously deleted.
Source
Thrown at backend/routes/profiles.py:260
return profile
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
finally:
Path(tmp_path).unlink(missing_ok=True)
@router.get("/profiles/{profile_id}/avatar")
async def get_profile_avatar(
profile_id: str,
db: Session = Depends(get_db),
):
"""Get avatar image for a profile."""
profile = await profiles.get_profile(profile_id, db)
if not profile:
raise HTTPException(status_code=404, detail="Profile not found")
if not profile.avatar_path:
raise HTTPException(status_code=404, detail="No avatar found for this profile")
avatar_path = config.resolve_storage_path(profile.avatar_path)
if avatar_path is None or not avatar_path.exists():
raise HTTPException(status_code=404, detail="Avatar file not found")
return FileResponse(avatar_path)
@router.delete("/profiles/{profile_id}/avatar")
async def delete_profile_avatar(
profile_id: str,
db: Session = Depends(get_db),
):
"""Delete avatar image for a profile."""
success = await profiles.delete_avatar(profile_id, db)
if not success:
raise HTTPException(status_code=404, detail="Profile not found or no avatar to delete")
return {"message": "Avatar deleted successfully"}View on GitHub (pinned to 51f49dea19)
Solutions
- Treat this 404 as 'use default avatar' on the client -- it is a normal state, not an error.
- If an avatar is expected, upload one via POST /profiles/{profile_id}/avatar first.
- Distinguish the two 404 detail strings ('No avatar found' vs 'Avatar file not found') to drive different UX.
Defensive patterns
Strategy: fallback
Validate before calling
async def avatar_url_or_default(client, profile_id, fallback):
profile = (await client.get(f"/profiles/{profile_id}")).json()
if not profile.get("avatar_path"):
return fallback
return f"/profiles/{profile_id}/avatar" Type guard
def has_avatar(profile_dict: dict) -> bool:
"""True only when the profile actually has an avatar path set."""
return bool(profile_dict.get("avatar_path")) Try / catch
resp = await client.get(f"/profiles/{profile_id}/avatar")
if resp.status_code == 404 and resp.json()["detail"] == "No avatar found for this profile":
use_default_avatar() # normal state, not an error
else:
resp.raise_for_status() Prevention
- Inspect avatar_path on the profile dict; only call /avatar when it is truthy.
- Treat 'No avatar found' as a normal default-avatar state in the UI.
- Distinguish it from 'Avatar file not found', which signals real drift.
When it happens
Trigger: Calling the avatar endpoint on a freshly created profile before any upload; after DELETE /profiles/{id}/avatar succeeded; on a profile imported from a ZIP that did not include an avatar.
Common situations: UI always calls /avatar for every profile and expects some to have none; import flow that omits avatar blobs.
Related errors
- Avatar file not found
- Profile not found or no avatar to delete
- Generation failed; no audio available
- Sample not found
- Capture not found
AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12).
Data as JSON: /api/errors/c3303bc72b3afb1d.
Report an issue: GitHub.