unslothai/unsloth · error · TranscriptUnavailable

YouTube returned unreadable caption data.

Error message

YouTube returned unreadable caption data.

What it means

TranscriptUnavailable raised when the caption response body cannot be decoded as UTF-8 or parsed as JSON. Analogous to error 789 but for the caption json3 payload: bytes were received and non-empty, but json.loads fails (UnicodeDecodeError/ValueError, chained from the original error).

Source

Thrown at studio/backend/core/youtube_transcript.py:283

            location = response.headers.get("location")
            if response.is_redirect and location:
                url = urljoin(url, location)
                _validated_caption_url(url)
                continue
            response.raise_for_status()
            body = await _read_capped(
                response, _MAX_CAPTION_BYTES, "This video's captions are too large to attach."
            )
        break
    else:
        raise TranscriptUnavailable("YouTube redirected the caption request too many times.")
    if not body:
        raise TranscriptUnavailable("YouTube returned no caption text for this video.")

    try:
        payload = json.loads(body.decode("utf-8"))
    except (UnicodeDecodeError, ValueError) as error:
        raise TranscriptUnavailable("YouTube returned unreadable caption data.") from error
    events = payload.get("events") if isinstance(payload, dict) else None
    return _flatten_events(events or [])


def _flatten_events(events: list[Any]) -> str:
    lines: list[str] = []
    for event in events:
        if not isinstance(event, dict):
            continue
        # aAppend cues carry only the rolling-window newline between ASR lines.
        if event.get("aAppend") == 1:
            continue
        segments = event.get("segs")
        if not isinstance(segments, list):
            continue
        joined = "".join(
            str(segment.get("utf8") or "") for segment in segments if isinstance(segment, dict)
        )

View on GitHub (pinned to 203007d190)

Solutions

  1. Retry with backoff or a different egress IP.
  2. Log body[:200] to identify what was actually returned; HTML indicates blocking/consent issues rather than a parse bug.
  3. Slow down request rates to avoid triggering block pages.
Defensive patterns

Strategy: retry

Try / catch

for attempt in range(2):
    try:
        transcript = await fetch_transcript(video_id)
        break
    except TranscriptUnavailable as e:
        if "unreadable caption data" in str(e) and attempt == 0:
            continue
        raise

Prevention

When it happens

Trigger: Caption endpoint returning HTML (error/consent page) or binary/garbage content instead of json3; truncated bodies; encoding mismatches. Distinct from 793 (empty body) — here the body is present but unparseable.

Common situations: Soft-blocks or interstitials served on the caption URL; transient payload corruption; proxy interference.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/a4e321bfe85c2ac2. Report an issue: GitHub.