2727 get_async_session ,
2828)
2929from app .podcasts .generation .brief import propose_brief
30- from app .podcasts .persistence import Podcast , PodcastRepository
30+ from app .podcasts .persistence import Podcast , PodcastRepository , PodcastStatus
3131from app .podcasts .service import (
3232 InvalidTransitionError ,
3333 PodcastService ,
3434 PreconditionFailedError ,
3535 SpecConflictError ,
3636)
37- from app .podcasts .storage import open_audio_stream , purge_audio
37+ from app .podcasts .storage import audio_exists , open_audio_stream , purge_audio
3838from app .podcasts .tasks import draft_transcript_task
3939from app .podcasts .tts import get_text_to_speech
4040from app .podcasts .voices import (
@@ -272,6 +272,11 @@ async def stream_podcast(
272272 podcast = await _load (session , user , podcast_id , Permission .PODCASTS_READ )
273273
274274 if podcast .storage_key :
275+ # Verify first so a missing object is a 404, not a mid-stream crash.
276+ if not await audio_exists (podcast ):
277+ raise HTTPException (
278+ status_code = 404 , detail = "Podcast audio is no longer available"
279+ )
275280 return StreamingResponse (
276281 open_audio_stream (podcast ),
277282 media_type = "audio/mpeg" ,
@@ -295,7 +300,10 @@ def iterfile():
295300 },
296301 )
297302
298- raise HTTPException (status_code = 404 , detail = "Podcast audio not found" )
303+ # No audio: terminal states never will have any, otherwise it's in flight.
304+ if PodcastStatus (podcast .status ).is_terminal :
305+ raise HTTPException (status_code = 404 , detail = "Podcast audio not found" )
306+ raise HTTPException (status_code = 409 , detail = "Podcast audio is not ready yet" )
299307
300308
301309async def _require (
0 commit comments