lfnovo/open-notebook · error · HTTPException

Failed to retry episode

Error message

Failed to retry episode

What it means

Generic 500 raised by the retry-podcast-episode endpoint when an unexpected (non-HTTP, non-OpenNotebook) exception escapes while retrying a failed podcast episode processing job. The original exception is logged server-side but not surfaced to the client.

Source

Thrown at api/routers/podcasts.py:403

        await episode.delete()

        # Submit a new job
        job_id = await PodcastService.submit_generation_job(
            episode_profile_name=ep_profile_name,
            speaker_profile_name=sp_profile_name,
            episode_name=episode_name,
            content=content,
        )

        return {"job_id": job_id, "message": "Retry submitted successfully"}

    except HTTPException:
        raise
    except OpenNotebookError:
        raise
    except Exception as e:
        logger.error(f"Error retrying podcast episode: {str(e)}")
        raise HTTPException(
            status_code=500, detail="Failed to retry episode"
        )


@router.delete("/podcasts/episodes/{episode_id}")
async def delete_podcast_episode(episode_id: str):
    """Delete a podcast episode and its associated audio file"""
    try:
        # Get the episode first to check if it exists and get the audio file path
        episode = await PodcastService.get_episode(episode_id)

        # Delete the physical audio file if it exists
        _delete_episode_audio(episode, episode_id)

        # Delete the episode from the database
        await episode.delete()

        logger.info(f"Deleted podcast episode: {episode_id}")

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Check API logs for the 'Error retrying podcast episode:' line to see the real exception
  2. Verify the worker is running (make worker-start) and SurrealDB is up (make database)
  3. Confirm the episode_id exists and its source record is intact
  4. Re-ingest the podcast episode if its stored data is corrupted

Example fix

// before
const r = await fetch(`/api/podcasts/episodes/${id}/retry`);
// after
const r = await fetch(`/api/podcasts/episodes/${id}/retry`);
if (r.status === 500) {
  console.error('Retry failed; check server logs for root cause');
}
Defensive patterns

Strategy: try-catch

Validate before calling

const ep = await fetch(`/api/podcasts/episodes/${id}`).then(r => r.ok ? r.json() : null);
if (!ep) throw new Error('Episode not found');

Try / catch

try {
  await retryEpisode(id);
} catch (e) {
  if (e.status === 500) { /* inspect server log; surface generic retry message */ }
  throw e;
}

Prevention

When it happens

Trigger: POST to /api/podcasts/episodes/{episode_id}/retry when the underlying retry logic raises anything outside HTTPException/OpenNotebookError — e.g. the episode record is missing/malformed, the job queue is unreachable, or a worker dependency throws.

Common situations: SurrealDB connection dropped, surreal-commands worker not running or stuck, episode row with corrupted JSON fields, version mismatch after upgrade between API and worker.

Related errors


AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27). Data as JSON: /api/errors/fc52bbf121599ca8. Report an issue: GitHub.