ytdl-org/youtube-dl · error · ExtractorError

Failed to find episode data

Error message

Failed to find episode data

What it means

Raised by CallinIE when the parsed Next.js __NEXT_DATA__ JSON has no dict at props.pageProps.episode (traverse_obj returns None). The extractor relies entirely on that embedded structure to get title, m3u8 URL, and show metadata, so without it extraction cannot continue.

Source

Thrown at youtube_dl/extractor/callin.py:53

            'channel_url': 'https://callin.com/show/the-debrief-with-briahna-joy-gray-siiFDzGegm',
        }
    }]

    def _search_nextjs_data(self, webpage, video_id, transform_source=None, fatal=True, **kw):
        return self._parse_json(
            self._search_regex(
                r'(?s)<script[^>]+id=[\'"]__NEXT_DATA__[\'"][^>]*>([^<]+)</script>',
                webpage, 'next.js data', fatal=fatal, **kw),
            video_id, transform_source=transform_source, fatal=fatal)

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)

        next_data = self._search_nextjs_data(webpage, video_id)
        episode = traverse_obj(next_data, ('props', 'pageProps', 'episode'), expected_type=dict)
        if not episode:
            raise ExtractorError('Failed to find episode data')

        title = episode.get('title') or self._og_search_title(webpage)
        description = episode.get('description') or self._og_search_description(webpage)

        formats = []
        formats.extend(self._extract_m3u8_formats(
            episode.get('m3u8'), video_id, 'mp4',
            entry_protocol='m3u8_native', fatal=False))
        self._sort_formats(formats)

        channel = try_get(episode, lambda x: x['show']['title'], compat_str)
        channel_url = try_get(episode, lambda x: x['show']['linkObj']['resourceUrl'], compat_str)

        return {
            'id': video_id,
            'title': title,
            'description': description,
            'formats': formats,

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Confirm the URL is a real episode page (it should play in a plain browser).
  2. Open the page source and search for __NEXT_DATA__; if 'episode' is absent, the data layout changed — switch to yt-dlp or a newer extractor.
  3. If the show link redirects, follow the redirect and use the final URL.
  4. Report the breakage / patch the traverse path to wherever the episode object now lives.

Example fix

# example: make extraction resilient to a moved key
episode = (traverse_obj(next_data, ('props', 'pageProps', 'episode'), expected_type=dict)
           or traverse_obj(next_data, ('props', 'pageProps', 'data', 'episode'), expected_type=dict))
Defensive patterns

Strategy: validation

Validate before calling

import json, re
def has_episode_data(html):
    m = re.search(r'<script[^>]+id="__NEXT_DATA__"[^>]*>([^<]+)</script>', html)
    if not m:
        return False
    data = json.loads(m.group(1))
    return isinstance(data.get('props', {}).get('pageProps', {}).get('episode'), dict)

Type guard

def is_episode_page(next_data):
    ep = next_data.get('props', {}).get('pageProps', {}).get('episode') if isinstance(next_data, dict) else None
    return isinstance(ep, dict) and bool(ep.get('m3u8'))

Try / catch

from youtube_dl.utils import ExtractorError
try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'Failed to find episode data' in str(e):
        mark_as_not_an_episode(url)  # do not retry
    else:
        raise

Prevention

When it happens

Trigger: Downloading a callin.com URL that is not an episode page (a show/landing/login page), a page rendered differently (SSR structure changed or data moved), or an episode that was removed so pageProps no longer contains 'episode'.

Common situations: Site redesign moving the episode payload to a different key or to client-side fetching; passing a stub or preview URL; episode unlisted/deleted.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/0144d910de351118. Report an issue: GitHub.