{"record":{"id":"a087459a0b8e3697","repo":"lfnovo/open-notebook","slug":"failed-to-duplicate-episode-profile","errorCode":null,"errorMessage":"Failed to duplicate episode profile","messagePattern":"Failed to duplicate episode profile","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"api/routers/episode_profiles.py","lineNumber":276,"sourceCode":"            transcript_llm=original.transcript_llm,\n            language=original.language,\n            default_briefing=original.default_briefing,\n            num_segments=original.num_segments,\n            max_tokens=original.max_tokens,\n        )\n\n        await duplicate.save()\n        return _profile_to_response(\n            duplicate, await _speaker_name_for(duplicate.speaker_config)\n        )\n\n    except HTTPException:\n        raise\n    except OpenNotebookError:\n        raise\n    except Exception as e:\n        logger.error(f\"Failed to duplicate episode profile: {e}\")\n        raise HTTPException(\n            status_code=500, detail=\"Failed to duplicate episode profile\"\n        )\n","sourceCodeStart":258,"sourceCodeEnd":279,"githubUrl":"https://github.com/lfnovo/open-notebook/blob/a7de90d38aaf18ee85fd661854d35c11e44613e2/api/routers/episode_profiles.py#L258-L279","documentation":"Generic 500 raised when duplicating an episode profile fails unexpectedly — typically constructing or saving the copy (e.g., name collision on '<name> - Copy').","triggerScenarios":"POST duplicate where db.save() of the new record fails: unique-name conflict because '<name> - Copy' already exists, DB outage, or serialization of fields copied from the original.","commonSituations":"Duplicating the same profile twice (both copies get the identical ' - Copy' name); DB schema constraints; DB downtime.","solutions":["Check logs for the exact cause on 'Failed to duplicate episode profile'","If a name collision, rename the existing copy first or edit after duplicating","Verify DB health and retry","Consider making duplicate names unique (append a counter) at the API level"],"exampleFix":"// before\nduplicate = EpisodeProfile(name=f\"{original.name} - Copy\", ...)\n// after (unique suffix)\nimport uuid\nduplicate = EpisodeProfile(name=f\"{original.name} - Copy {uuid.uuid4().hex[:4]}\", ...)","handlingStrategy":"try-catch","validationCode":"copies = {p[\"name\"] for p in (await client.get(\"/api/episode-profiles\")).json()}\nnew_name = f\"{source_name} - Copy\"\nn = 2\nwhile new_name in copies:\n    new_name = f\"{source_name} - Copy ({n})\"; n += 1","typeGuard":null,"tryCatchPattern":"try:\n    await client.post(f\"/api/episode-profiles/{profile_id}/duplicate\")\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code >= 500:\n        # likely name collision on '<name> - Copy' — rename existing copy and retry\n        await rename_existing_copy(source_name)\n        await client.post(f\"/api/episode-profiles/{profile_id}/duplicate\")\n    raise","preventionTips":["Don't duplicate the same profile twice without renaming","Rename duplicates to meaningful unique names","Consider patching the API to generate unique copy names"],"tags":["http-500","internal-error","episode-profile","duplicate","unique-constraint"],"backgroundTag":"internal-server-error","analyzedSha":"a7de90d38aaf18ee85fd661854d35c11e44613e2","analyzedAt":"2026-08-27T02:39:58.166Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}