ytdl-org/youtube-dl · error · ExtractorError

%s

Error message

%s

What it means

Raised by the Limelight extractor when the PlaylistService API returns HTTP 403: the 403 body's detail.contentAccessPermission value is re-raised verbatim as the error message (with 'CountryDisabled' upgraded to a geo-restriction error). It is expected=True and encodes the publisher's access-permission refusal.

Source

Thrown at youtube_dl/extractor/limelight.py:79

                smuggle('limelight:media:%s' % video_id),
                LimelightMediaIE.ie_key(), video_id))
        return entries

    def _call_playlist_service(self, item_id, method, fatal=True, referer=None):
        headers = {}
        if referer:
            headers['Referer'] = referer
        try:
            return self._download_json(
                self._PLAYLIST_SERVICE_URL % (self._PLAYLIST_SERVICE_PATH, item_id, method),
                item_id, 'Downloading PlaylistService %s JSON' % method,
                fatal=fatal, headers=headers)
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                error = self._parse_json(e.cause.read().decode(), item_id)['detail']['contentAccessPermission']
                if error == 'CountryDisabled':
                    self.raise_geo_restricted()
                raise ExtractorError(error, expected=True)
            raise

    def _extract(self, item_id, pc_method, mobile_method, referer=None):
        pc = self._call_playlist_service(item_id, pc_method, referer=referer)
        mobile = self._call_playlist_service(
            item_id, mobile_method, fatal=False, referer=referer)
        return pc, mobile

    def _extract_info(self, pc, mobile, i, referer):
        get_item = lambda x, y: try_get(x, lambda x: x[y][i], dict) or {}
        pc_item = get_item(pc, 'playlistItems')
        mobile_item = get_item(mobile, 'mediaList')
        video_id = pc_item.get('mediaId') or mobile_item['mediaId']
        title = pc_item.get('title') or mobile_item['title']

        formats = []
        urls = []
        for stream in pc_item.get('streams', []):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. If the message says CountryDisabled, use a proxy in an allowed country
  2. If domain-restricted, open the video from the original embedding page (or pass its URL as Referer via --add-headers)
  3. Confirm the media id is still published in the publisher's Limelight dashboard
  4. Update to yt-dlp for improved Limelight handling

Example fix

# supply the embedding page as referer
# yt-dlp --add-headers 'Referer:https://original-site.example/page' 'https://assets.delvenetworks.com/...'
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    msg = str(e)
    if 'CountryDisabled' in msg:
        retry_with_regional_proxy(url)
    elif 'DomainDisabled' in msg or 'PermissionDenied' in msg:
        retry_with_referer(url, embedding_page_url)
    else:
        raise

Prevention

When it happens

Trigger: Requesting a Limelight media/channel id whose PlaylistService call (playlist.<method>.json) responds 403 with a contentAccessPermission such as 'CountryDisabled', 'DomainDisabled', or expired/unpublished media — e.g. embeds restricted to the publisher's own domain or region.

Common situations: Videos restricted to specific domains (referrers) opened directly; geo-disabled media; unpublished or deleted channel items still referenced by old pages; missing Referer when the embed requires it.

Related errors


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