unslothai/unsloth · warning · TranscriptUnavailable
This video's captions are empty.
Error message
This video's captions are empty.
What it means
TranscriptUnavailable raised after a caption track was successfully selected and fetched, but the resulting text was empty (falsy). The track exists on YouTube's side but yields no usable cues, e.g. all events were filtered out or the payload decoded to nothing.
Source
Thrown at studio/backend/core/youtube_transcript.py:130
async with httpx.AsyncClient(timeout = _TIMEOUT, follow_redirects = True) as client:
player = await _fetch_player(client, video_id)
status = (player.get("playabilityStatus") or {}).get("status")
if status not in (None, "OK"):
raise TranscriptUnavailable(
(player.get("playabilityStatus") or {}).get("reason")
or "YouTube will not play this video."
)
tracklist = (player.get("captions") or {}).get("playerCaptionsTracklistRenderer") or {}
tracks = [t for t in (tracklist.get("captionTracks") or []) if t.get("baseUrl")]
if not tracks:
raise TranscriptUnavailable("This video has no captions.")
track = _select_track(tracks, tracklist, languages)
text = await _fetch_track_text(client, str(track["baseUrl"]))
if not text:
raise TranscriptUnavailable("This video's captions are empty.")
text, truncated = _truncate_transcript(text)
details = player.get("videoDetails") or {}
return Transcript(
video_id = video_id,
title = str(details.get("title") or ""),
author = str(details.get("author") or ""),
length_seconds = _as_int(details.get("lengthSeconds")),
language = _track_label(track),
language_code = str(track.get("languageCode") or ""),
is_generated = track.get("kind") == "asr",
text = text,
truncated = truncated,
)
def _truncate_transcript(text: str) -> tuple[str, bool]:
"""Bound the transcript so a long video cannot swallow the model's context."""View on GitHub (pinned to 203007d190)
Solutions
- Try a different language track by passing languages= to fetch_transcript so another track is selected.
- Retry once — transient empty responses occur under load.
- Treat as 'no transcript' and skip or fall back to local transcription, same as the no-captions case.
Example fix
# before
transcript = await fetch_transcript(video_id) # selected track is empty -> raises
# after
transcript = await fetch_transcript(video_id, languages=("en", "en-US", "")) Defensive patterns
Strategy: fallback
Try / catch
try:
transcript = await fetch_transcript(video_id, languages=("en", "en-US"))
except TranscriptUnavailable as e:
if "captions are empty" in str(e):
transcript = await fetch_transcript(video_id) # retry default track once
else:
raise Prevention
- Pass an explicit languages priority list so a dead track is not selected first.
- Treat empty captions like missing captions in product logic (offer fallback transcription).
- Retry once before giving up — empty track bodies are often transient.
When it happens
Trigger: A caption track whose json3 payload contains only events that flatten to empty text (e.g. only aAppend rolling-newline markers); tracks that exist but were never populated; edge-case payload shapes after the flatten step.
Common situations: Placeholder/disabled caption tracks; extremely short videos; YouTube serving an effectively empty track for restricted content.
Related errors
- YouTube returned no caption text for this video.
- load timed out (last progress: {prog})
- That is not a YouTube video link.
- YouTube will not play this video.
- This video has no captions.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/d13e3cc6a05f021f.
Report an issue: GitHub.