{"record":{"id":"c3303bc72b3afb1d","repo":"jamiepine/voicebox","slug":"no-avatar-found-for-this-profile","errorCode":null,"errorMessage":"No avatar found for this profile","messagePattern":"No avatar found for this profile","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"info","filePath":"backend/routes/profiles.py","lineNumber":260,"sourceCode":"        return profile\n    except ValueError as e:\n        raise HTTPException(status_code=400, detail=str(e))\n    finally:\n        Path(tmp_path).unlink(missing_ok=True)\n\n\n@router.get(\"/profiles/{profile_id}/avatar\")\nasync def get_profile_avatar(\n    profile_id: str,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Get avatar image for a profile.\"\"\"\n    profile = await profiles.get_profile(profile_id, db)\n    if not profile:\n        raise HTTPException(status_code=404, detail=\"Profile not found\")\n\n    if not profile.avatar_path:\n        raise HTTPException(status_code=404, detail=\"No avatar found for this profile\")\n\n    avatar_path = config.resolve_storage_path(profile.avatar_path)\n    if avatar_path is None or not avatar_path.exists():\n        raise HTTPException(status_code=404, detail=\"Avatar file not found\")\n\n    return FileResponse(avatar_path)\n\n\n@router.delete(\"/profiles/{profile_id}/avatar\")\nasync def delete_profile_avatar(\n    profile_id: str,\n    db: Session = Depends(get_db),\n):\n    \"\"\"Delete avatar image for a profile.\"\"\"\n    success = await profiles.delete_avatar(profile_id, db)\n    if not success:\n        raise HTTPException(status_code=404, detail=\"Profile not found or no avatar to delete\")\n    return {\"message\": \"Avatar deleted successfully\"}","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/routes/profiles.py#L242-L278","documentation":"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.","triggerScenarios":"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.","commonSituations":"UI always calls /avatar for every profile and expects some to have none; import flow that omits avatar blobs.","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."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"async def avatar_url_or_default(client, profile_id, fallback):\n    profile = (await client.get(f\"/profiles/{profile_id}\")).json()\n    if not profile.get(\"avatar_path\"):\n        return fallback\n    return f\"/profiles/{profile_id}/avatar\"","typeGuard":"def has_avatar(profile_dict: dict) -> bool:\n    \"\"\"True only when the profile actually has an avatar path set.\"\"\"\n    return bool(profile_dict.get(\"avatar_path\"))","tryCatchPattern":"resp = await client.get(f\"/profiles/{profile_id}/avatar\")\nif resp.status_code == 404 and resp.json()[\"detail\"] == \"No avatar found for this profile\":\n    use_default_avatar()       # normal state, not an error\nelse:\n    resp.raise_for_status()","preventionTips":["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."],"tags":["fastapi","avatar","not-found","ux"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}