yt-dlp/yt-dlp · error · ExtractorError

traverse_obj(smil, (f' ref/@abstract', ..., any))

Error message

traverse_obj(smil, (f'{ns}ref/@abstract', ..., any))

What it means

Thrown by NBCUniversalBaseIE._download_nbcu_smil_and_extract_m3u8_url (yt_dlp/extractor/nbc.py:60) when thePlatform SMIL manifest (link.theplatform.com/s/<tp_path>?...&format=SMIL&manifest=m3u&switch=HLSServiceSecure) contains no m3u8 video/@src. The exception MESSAGE is read out of the SMIL document itself - the ref element's @abstract attribute - so it carries thePlatform's own fault text (expiry notice, rights error, etc.). It is flagged expected only when the SMIL's exception param equals 'Expired'.

Solutions

  1. Read the text in the error message - it is the provider's own reason (expired, rights removed, geo)
  2. Update yt-dlp nightly; theplatform token handling is patched frequently
  3. If it is geo-related, retry from a US IP: --proxy (and see --geo-verification-proxy)
  4. Fetch the video page fresh so yt-dlp generates current theplatform tokens instead of reusing an old link
  5. If the asset is DRM-only there is nothing yt-dlp can download
Defensive patterns

Strategy: try-catch

Try / catch

from yt_dlp.utils import ExtractorError, GeoRestrictedError
try:
    info = ydl.extract_info(url, download=False)
except GeoRestrictedError:
    log.info('geo-blocked; retry via US proxy')
except ExtractorError as e:
    if e.expected and 'expired' in str(e).lower():
        refresh_page_tokens(url)  # re-fetch the NBC page for new theplatform tokens
    else:
        raise  # message text comes from the SMIL @abstract: read it

Prevention

When it happens

Trigger: The SMIL GET returns a fault document instead of a playable manifest: expired theplatform auth token (exception 'Expired'), deleted/expired media, DRM-only asset with no HLS rendition, or a geo fault (GeoLocationBlocked is converted to raise_geo_restricted just above this line).

Common situations: Reusing stale mxplayer/theplatform tokenized URLs copied from old pages or caches; NBC/NBC Sports content removed after the broadcast window; non-US IPs receiving geo-fault SMILs; premium DRM streams.

Related errors


AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22). Data as JSON: /api/errors/014b411260f00b70. Report an issue: GitHub.

Appendix: source

Thrown at yt_dlp/extractor/nbc.py:60

    def _download_nbcu_smil_and_extract_m3u8_url(self, tp_path, video_id, query):
        smil = self._download_xml(
            f'https://link.theplatform.com/s/{tp_path}', video_id,
            'Downloading SMIL manifest', 'Failed to download SMIL manifest', query={
                **query,
                'format': 'SMIL',  # XXX: Do not confuse "format" with "formats"
                'manifest': 'm3u',
                'switch': 'HLSServiceSecure',  # Or else we get broken mp4 http URLs instead of HLS
            }, headers=self.geo_verification_headers())

        ns = f'//{{{default_ns}}}'
        if url := traverse_obj(smil, (f'{ns}video/@src', lambda _, v: determine_ext(v) == 'm3u8', any)):
            return url

        exc = traverse_obj(smil, (f'{ns}param', lambda _, v: v.get('name') == 'exception', '@value', any))
        if exc == 'GeoLocationBlocked':
            self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
        raise ExtractorError(traverse_obj(smil, (f'{ns}ref/@abstract', ..., any)), expected=exc == 'Expired')

    def _extract_nbcu_formats_and_subtitles(self, tp_path, video_id, query):
        # formats='mpeg4' will return either a working m3u8 URL or an m3u8 template for non-DRM HLS
        # formats='m3u+none,mpeg4' may return DRM HLS but w/the "folders" needed for non-DRM template
        query['formats'] = 'm3u+none,mpeg4'
        orig_m3u8_url = m3u8_url = self._download_nbcu_smil_and_extract_m3u8_url(tp_path, video_id, query)

        if mobj := re.fullmatch(self._M3U8_RE, m3u8_url):
            query['formats'] = 'mpeg4'
            m3u8_tmpl = self._download_nbcu_smil_and_extract_m3u8_url(tp_path, video_id, query)
            # Example: https://vod-lf-oneapp-prd.akamaized.net/prod/video/{folders}master_hls.m3u8
            if '{folders}' in m3u8_tmpl:
                self.write_debug('Found m3u8 URL template, formatting URL path')
            m3u8_url = m3u8_tmpl.format(folders=mobj.group('folders'))

        if '/mpeg_cenc' in m3u8_url or '/mpeg_cbcs' in m3u8_url:
            self.report_drm(video_id)

View on GitHub (pinned to 81ecd58b13)