{"record":{"id":"a0ac8f3a21af7ce2","repo":"lfnovo/open-notebook","slug":"failed-to-fetch-episode-profiles","errorCode":null,"errorMessage":"Failed to fetch episode profiles","messagePattern":"Failed to fetch episode profiles","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"api/routers/episode_profiles.py","lineNumber":93,"sourceCode":"@router.get(\"/episode-profiles\", response_model=List[EpisodeProfileResponse])\nasync def list_episode_profiles():\n    \"\"\"List all available episode profiles\"\"\"\n    try:\n        profiles = await EpisodeProfile.get_all(order_by=\"name asc\")\n        speaker_names = await _speaker_names_by_id()\n        return [\n            _profile_to_response(\n                p, speaker_names.get(p.speaker_config) if p.speaker_config else None\n            )\n            for p in profiles\n        ]\n    except HTTPException:\n        raise\n    except OpenNotebookError:\n        raise\n    except Exception as e:\n        logger.error(f\"Failed to fetch episode profiles: {e}\")\n        raise HTTPException(\n            status_code=500, detail=\"Failed to fetch episode profiles\"\n        )\n\n\n@router.get(\"/episode-profiles/{profile_name}\", response_model=EpisodeProfileResponse)\nasync def get_episode_profile(profile_name: str):\n    \"\"\"Get a specific episode profile by name\"\"\"\n    try:\n        profile = await EpisodeProfile.get_by_name(profile_name)\n\n        if not profile:\n            raise HTTPException(\n                status_code=404, detail=f\"Episode profile '{profile_name}' not found\"\n            )\n\n        return _profile_to_response(\n            profile, await _speaker_name_for(profile.speaker_config)\n        )","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/lfnovo/open-notebook/blob/a7de90d38aaf18ee85fd661854d35c11e44613e2/api/routers/episode_profiles.py#L75-L111","documentation":"Generic 500 raised when listing episode profiles fails unexpectedly (non-OpenNotebookError exception). The real cause is logged with the profile-fetch context.","triggerScenarios":"GET /api/episode-profiles failing at the DB layer — SurrealDB unreachable, auth failure, or a deserialization problem turning malformed rows into EpisodeProfile objects.","commonSituations":"Database not started (make database), SurrealDB restarted without the API noticing, schema migration left half-applied, corrupted records.","solutions":["Check API logs for the logged exception detail","Confirm SurrealDB is running and reachable (make status)","Restart the API so migrations re-run and connections refresh","If a specific record fails to deserialize, inspect/repair it in the DB"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    profiles = await client.get(\"/api/episode-profiles\")\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code >= 500:\n        await wait_for_api_healthy()\n        profiles = await client.get(\"/api/episode-profiles\")\n    else:\n        raise","preventionTips":["Start tiers in order (database → api) before calling the API","Add health checks before batch operations","Surface API logs when 500s appear — detail is server-side only"],"tags":["http-500","internal-error","episode-profile","database"],"backgroundTag":"internal-server-error","analyzedSha":"a7de90d38aaf18ee85fd661854d35c11e44613e2","analyzedAt":"2026-08-27T02:39:58.166Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}