ytdl-org/youtube-dl · error · ExtractorError

Episode %s is not currently available

Error message

Episode %s is not currently available

What it means

Sibling of errors 45/46 in BBCCoUkIE._extract_from_legacy_playlist: the legacy playlist XML returns <noItems reason="noMedia"/> — the episode record exists but no playable media is attached at all (not a timing issue like pre/postAvailability). Raised expected=True as 'Episode %s is not currently available'.

Source

Thrown at youtube_dl/extractor/bbc.py:509

            'http://www.bbc.co.uk/iplayer/playlist/%s' % playlist_id, playlist_id)

    def _download_legacy_playlist_url(self, url, playlist_id=None):
        return self._download_xml(
            url, playlist_id, 'Downloading legacy playlist XML')

    def _extract_from_legacy_playlist(self, playlist, playlist_id):
        no_items = playlist.find('./{%s}noItems' % self._EMP_PLAYLIST_NS)
        if no_items is not None:
            reason = no_items.get('reason')
            if reason == 'preAvailability':
                msg = 'Episode %s is not yet available' % playlist_id
            elif reason == 'postAvailability':
                msg = 'Episode %s is no longer available' % playlist_id
            elif reason == 'noMedia':
                msg = 'Episode %s is not currently available' % playlist_id
            else:
                msg = 'Episode %s is not available: %s' % (playlist_id, reason)
            raise ExtractorError(msg, expected=True)

        for item in self._extract_items(playlist):
            kind = item.get('kind')
            if kind not in ('programme', 'radioProgramme'):
                continue
            title = playlist.find('./{%s}title' % self._EMP_PLAYLIST_NS).text
            description_el = playlist.find('./{%s}summary' % self._EMP_PLAYLIST_NS)
            description = description_el.text if description_el is not None else None

            def get_programme_id(item):
                def get_from_attributes(item):
                    for p in ('identifier', 'group'):
                        value = item.get(p)
                        if value and re.match(r'^[pb][\da-z]{7}$', value):
                            return value
                get_from_attributes(item)
                mediator = item.find('./{%s}mediator' % self._EMP_PLAYLIST_NS)
                if mediator is not None:

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Try the modern (non-legacy) extraction path / the programme's canonical page — the extractor prefers other sources first and only falls back to legacy, so hitting this means the modern path already failed for that id.
  2. Verify in a browser that the episode actually plays; if the page shows no player, the id is metadata-only.
  3. Filter such ids out of batch lists by checking the page for a player before extraction.
  4. Report persistent cases upstream if the page clearly plays media but extraction ends here.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(episode_url)
except ExtractorError as e:
    if 'is not currently available' in str(e):
        mark_unplayable(episode_url)  # metadata-only id; skip in future runs
    else:
        raise

Prevention

When it happens

Trigger: Extracting a programme id that the EMP backend knows about but that has no media streams attached: radio/news clips replaced by text, programmes with rights-cleared metadata but no stream, or ids that only ever carried metadata.

Common situations: Scraping programme pages that embed ids for non-video content; episodes whose audio/video rights lapsed entirely; BBC data inconsistencies where a page links an id the media backend does not serve.

Related errors


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