ytdl-org/youtube-dl · error · ExtractorError

%s said: %s

Error message

%s said: %s

What it means

Raised by BiliBiliBangumiIE._report_error when a Bangumi API call returns a result dict containing a 'message' key: the error interpolates the extractor name ('Bilibili Bangumi') and the API's own message text (e.g. 'Bilibili Bangumi said: Sorry, the video is only available in mainland China'). Expected=True — a server-side rejection carried through verbatim.

Source

Thrown at youtube_dl/extractor/bilibili.py:117

                'timestamp': 1488382634,
                'upload_date': '20170301',
            },
            'params': {
                'skip_download': True,  # Test metadata only
            },
        }]
    }, {
        # new BV video id format
        'url': 'https://www.bilibili.com/video/BV1JE411F741',
        'only_matching': True,
    }]

    _APP_KEY = 'iVGUTjsxvpLeuDCf'
    _BILIBILI_KEY = 'aHRmhWMLkdeMuILqORnYZocwMBpMEOdt'

    def _report_error(self, result):
        if 'message' in result:
            raise ExtractorError('%s said: %s' % (self.IE_NAME, result['message']), expected=True)
        elif 'code' in result:
            raise ExtractorError('%s returns error %d' % (self.IE_NAME, result['code']), expected=True)
        else:
            raise ExtractorError('Can\'t extract Bangumi episode ID')

    def _real_extract(self, url):
        url, smuggled_data = unsmuggle_url(url, {})

        mobj = re.match(self._VALID_URL, url)
        video_id = mobj.group('id') or mobj.group('id_bv')
        anime_id = mobj.group('anime_id')
        webpage = self._download_webpage(url, video_id)

        if 'anime/' not in url:
            cid = self._search_regex(
                r'\bcid(?:["\']:|=)(\d+)', webpage, 'cid',
                default=None
            ) or compat_parse_qs(self._search_regex(

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the interpolated message — it is Bilibili's own reason; 'mainland China' messages require a CN IP (VPN) or a different source.
  2. For removed episodes, check the bangumi page in a browser for replacement ids.
  3. If all requests fail with auth-style messages, the bundled _APP_KEY/_BILIBILI_KEY may be stale — update them from the current web app and report upstream.
  4. Handle as expected in batch tools: log and skip rather than abort the run.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(bangumi_url)
except ExtractorError as e:
    msg = str(e)
    if 'said:' in msg:
        if 'mainland China' in msg:
            raise RegionBlocked(msg) from e
        log_api_rejection(bangumi_url, msg)  # server-side reason; not retryable as-is
    else:
        raise

Prevention

When it happens

Trigger: Calling the Bangumi playurl/season API (signed with _APP_KEY/_BILIBILI_KEY) for content the API refuses: region-locked videos for non-mainland-China IPs, removed episodes, or parameter errors — any response whose JSON includes a non-empty 'message' field hits this branch before the code branch.

Common situations: Non-CN IPs extracting region-locked bangumi (the dominant case); episodes pulled for licensing reasons; stale APP_KEY/signing secret after Bilibili rotated it, causing auth-reject messages; wrong anime/episode ids producing API error messages.

Related errors


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