ytdl-org/youtube-dl · error · ExtractorError

error['description']

Error message

error['description']

What it means

Raised by the FOX extractor when fetching the video's release URL (video['url']) returns 403 and the error body does not indicate GeoLocationBlocked (that case raises a geo error instead). The body's 'description' field is surfaced as an expected error. This guards the second-stage playback-URL fetch, after the vodplayer metadata call already succeeded.

Source

Thrown at youtube_dl/extractor/fox.py:107

                    'login', None, json.dumps({
                        'deviceId': compat_str(uuid.uuid4()),
                    }).encode())['accessToken']

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

        video = self._call_api('vodplayer/' + video_id, video_id)

        title = video['name']
        release_url = video['url']
        try:
            m3u8_url = self._download_json(release_url, video_id)['playURL']
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                error = self._parse_json(e.cause.read().decode(), video_id)
                if error.get('exception') == 'GeoLocationBlocked':
                    self.raise_geo_restricted(countries=['US'])
                raise ExtractorError(error['description'], expected=True)
            raise
        formats = self._extract_m3u8_formats(
            m3u8_url, video_id, 'mp4',
            entry_protocol='m3u8_native', m3u8_id='hls')
        self._sort_formats(formats)

        data = try_get(
            video, lambda x: x['trackingData']['properties'], dict) or {}

        duration = int_or_none(video.get('durationInSeconds')) or int_or_none(
            video.get('duration')) or parse_duration(video.get('duration'))
        timestamp = unified_timestamp(video.get('datePublished'))
        creator = data.get('brand') or data.get('network') or video.get('network')
        series = video.get('seriesName') or data.get(
            'seriesName') or data.get('show')

        subtitles = {}
        for doc_rel in video.get('documentReleases', []):

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the description text — it usually states the concrete rejection reason
  2. Retry immediately with fresh cookies and a US IP so the release-URL session stays valid
  3. Update to yt-dlp, whose FOX handling of release URLs and tokens is more current
  4. If the description indicates subscription-only preview, supply cable-provider cookies as for other FOX errors

Example fix

# before
youtube_dl --cookies fox.txt 'https://www.fox.com/watch/show-episode/'
# ERROR: <CDN description text>

# after
yt-dlp --cookies fox.txt 'https://www.fox.com/watch/show-episode/'
Defensive patterns

Strategy: retry

Try / catch

try:
    info = ydl.extract_info(url)
except ExtractorError as e:
    if 'GeoLocationBlocked' not in str(e) and caused_by_403(e):
        retry_once_with_fresh_cookies(url)  # token/session staleness often transient

Prevention

When it happens

Trigger: _download_json(release_url) raises with a compat_HTTPError 403; the JSON error has no exception == 'GeoLocationBlocked', so error['description'] is raised. Happens when the CDN releasing the stream rejects the session: expired playback token, DRM-only distribution, or regional restrictions reported without the geo exception code.

Common situations: Long pauses between metadata fetch and playback fetch in scripts; FOX serving the akamai release URL only to entitled US sessions; content replaced by preview-only trailers for non-subscribers.

Related errors


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