ytdl-org/youtube-dl · error · ExtractorError

%s

Error message

%s

What it means

Raised by the MGTV extractor when the pcweb.api.mgtv.com/player/video call fails with HTTP 401: the JSON error body is parsed, geo-restriction code 40005 is converted to a proper geo error, and any OTHER code becomes this raise with the API's own 'msg' text. Expected=True, so it is a service-refusal signal, not a bug.

Source

Thrown at youtube_dl/extractor/mgtv.py:55

        'url': 'https://w.mgtv.com/b/301817/3826653.html',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        tk2 = base64.urlsafe_b64encode(b'did=%s|pno=1030|ver=0.3.0301|clit=%d' % (compat_str(uuid.uuid4()).encode(), time.time()))[::-1]
        try:
            api_data = self._download_json(
                'https://pcweb.api.mgtv.com/player/video', video_id, query={
                    'tk2': tk2,
                    'video_id': video_id,
                }, headers=self.geo_verification_headers())['data']
        except ExtractorError as e:
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:
                error = self._parse_json(e.cause.read().decode(), None)
                if error.get('code') == 40005:
                    self.raise_geo_restricted(countries=self._GEO_COUNTRIES)
                raise ExtractorError(error['msg'], expected=True)
            raise
        info = api_data['info']
        title = info['title'].strip()
        stream_data = self._download_json(
            'https://pcweb.api.mgtv.com/player/getSource', video_id, query={
                'pm2': api_data['atc']['pm2'],
                'tk2': tk2,
                'video_id': video_id,
            }, headers=self.geo_verification_headers())['data']
        stream_domain = stream_data['stream_domain'][0]

        formats = []
        for idx, stream in enumerate(stream_data['stream']):
            stream_path = stream.get('url')
            if not stream_path:
                continue
            format_data = self._download_json(
                stream_domain + stream_path, video_id,

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the embedded msg — it is MGTV's stated reason in Chinese (e.g. 该视频已下线).
  2. If it is region related despite the code, route through a mainland-China proxy with --proxy.
  3. Verify the video plays at mgtv.com in a browser.
  4. Update youtube-dl / yt-dlp, as the tk2 signing and error-code mapping have evolved.
Defensive patterns

Strategy: try-catch

Type guard

def mgtv_is_geo_error(error_json):
    return isinstance(error_json, dict) and error_json.get('code') == 40005

Try / catch

try:
    info = ydl.extract_info(url, download=False)
except ExtractorError as e:
    msg = str(e)
    if 'This video is not available from your location' in msg or 'available in your area' in msg:
        retry_with_mainland_china_proxy(url)
    elif 'MGTV' in msg or 'mgtv' in msg:
        log_takedown(url, msg)  # site's own Chinese message; usually means removed
    else:
        raise

Prevention

When it happens

Trigger: _download_json raises ExtractorError whose cause is compat_HTTPError with code 401; the parsed body's 'code' != 40005, so error['msg'] is re-raised (e.g. video removed, copyright takedown). Non-401 network errors are re-raised untouched.

Common situations: Video taken down for licensing reasons on Hunan TV/MGTV; region-adjacent refusals that use a different code than 40005; stale video ids from old links; API changes returning 401 for requests missing required cookies.

Related errors


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