lfnovo/open-notebook · warning · HTTPException
Episode profile '{profile_id}' not found
Error message
Episode profile '{profile_id}' not found What it means
HTTP 404 from PUT /api/episode-profiles/{profile_id} when no profile with that record id exists.
Source
Thrown at api/routers/episode_profiles.py:185
except HTTPException:
raise
except OpenNotebookError:
raise
except Exception as e:
logger.error(f"Failed to create episode profile: {e}")
raise HTTPException(
status_code=500, detail="Failed to create episode profile"
)
@router.put("/episode-profiles/{profile_id}", response_model=EpisodeProfileResponse)
async def update_episode_profile(profile_id: str, profile_data: EpisodeProfileCreate):
"""Update an existing episode profile"""
try:
profile = await EpisodeProfile.get(profile_id)
if not profile:
raise HTTPException(
status_code=404, detail=f"Episode profile '{profile_id}' not found"
)
update_data = profile_data.model_dump(exclude_unset=True)
speaker_name: Optional[str] = None
if "speaker_config" in update_data:
speaker = await _resolve_speaker_config(update_data["speaker_config"])
update_data["speaker_config"] = str(speaker.id)
speaker_name = speaker.name
for field, value in update_data.items():
setattr(profile, field, value)
await profile.save()
if speaker_name is None:
speaker_name = await _speaker_name_for(profile.speaker_config)
return _profile_to_response(profile, speaker_name)
except HTTPException:View on GitHub (pinned to a7de90d38a)
Solutions
- GET /api/episode-profiles and use the record id (not name) from the response
- Confirm the profile still exists (not deleted concurrently)
- Ensure you're pointing at the right environment/database
Example fix
// before PUT /api/episode-profiles/my-profile-name // after PUT /api/episode-profiles/episode_profile:xk3d9z
Defensive patterns
Strategy: validation
Validate before calling
profiles = (await client.get("/api/episode-profiles")).json()
ids = {p["id"] for p in profiles}
if profile_id not in ids:
await refresh_profiles() # stale reference
raise ValueError(f"profile {profile_id} no longer exists") Type guard
def is_profile_id(pid: str, profiles: list[dict]) -> bool:
return pid in {p["id"] for p in profiles} Try / catch
try:
await client.put(f"/api/episode-profiles/{profile_id}", json=payload)
except httpx.HTTPStatusError as e:
if e.response.status_code == 404:
await refresh_profile_list() # profile gone; re-select
else:
raise Prevention
- Use record ids from the listing endpoint, never names, for update URLs
- Re-fetch the profile before editing to detect concurrent deletion
- Scope ids per environment — don't copy between databases
When it happens
Trigger: Updating a profile that was deleted, using a name instead of a record id in the URL, or an id from a different database/environment.
Common situations: Stale profile list in the UI after deletion in another session; copying ids between environments where SurrealDB record ids differ; passing the profile name where the record id is expected.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Episode profile '{profile_name}' not found
- Session not found
- Credential not found
- {embed_request.item_type} not found
- Rebuild command not found
AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27).
Data as JSON: /api/errors/7ac4e16078fdbfb0.
Report an issue: GitHub.