ytdl-org/youtube-dl · error · ExtractorError

Youku server reported error %i[: error_note]

Error message

Youku server reported error %i[: error_note]

What it means

YoukuIE raises this catch-all when the UPS get.json response has an error object whose note matches neither the geo-blocked ('因版权原因无法观看此视频') nor the private ('该视频被设为私密') pattern. The message interpolates the numeric error code and the raw server note, so it relays whatever upstream error Youku returned. It is not marked expected=True, so youtube-dl treats it as a generic extraction failure.

Source

Thrown at youtube_dl/extractor/youku.py:189

        data = self._download_json(
            'https://ups.youku.com/ups/get.json', video_id,
            'Downloading JSON metadata',
            query=basic_data_params, headers=headers)['data']

        error = data.get('error')
        if error:
            error_note = error.get('note')
            if error_note is not None and '因版权原因无法观看此视频' in error_note:
                raise ExtractorError(
                    'Youku said: Sorry, this video is available in China only', expected=True)
            elif error_note and '该视频被设为私密' in error_note:
                raise ExtractorError(
                    'Youku said: Sorry, this video is private', expected=True)
            else:
                msg = 'Youku server reported error %i' % error.get('code')
                if error_note is not None:
                    msg += ': ' + error_note
                raise ExtractorError(msg)

        # get video title
        video_data = data['video']
        title = video_data['title']

        formats = [{
            'url': stream['m3u8_url'],
            'format_id': self.get_format_name(stream.get('stream_type')),
            'ext': 'mp4',
            'protocol': 'm3u8_native',
            'filesize': int(stream.get('size')),
            'width': stream.get('width'),
            'height': stream.get('height'),
        } for stream in data['stream'] if stream.get('channel_type') != 'tail']
        self._sort_formats(formats)

        return {
            'id': video_id,

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Read the code and note in the message — they identify the real upstream reason (e.g. -6 typically means the video is unavailable); act on that reason (different video, login-required content, etc.).
  2. Reproduce the request to ups.youku.com with the same query params in a browser/curl and inspect data.error to confirm what Youku now returns.
  3. If the note text for a known case changed, add/adjust the substring match in the if/elif chain in youku.py so it maps to the friendly expected=True message.
  4. If params/headers are stale, compare with the current Youku web player request (referer, ctoken, cck, ua) and update basic_data_params/headers.

Example fix

// before
msg = 'Youku server reported error %i' % error.get('code')
if error_note is not None:
    msg += ': ' + error_note
raise ExtractorError(msg)

// after (treat a new known note as expected)
msg = 'Youku server reported error %i' % error.get('code')
if error_note is not None:
    msg += ': ' + error_note
raise ExtractorError(msg, expected=True)  # if the note is a user-content issue, not a bug
Defensive patterns

Strategy: try-catch

Validate before calling

import json, urllib.request

def youku_error_note(video_id, params):
    url = 'https://ups.youku.com/ups/get.json?' + urllib.parse.urlencode(params)
    with urllib.request.urlopen(url) as r:
        data = json.load(r).get('data', {})
    return data.get('error')  # None means extractable; else inspect code/note

Type guard

def is_known_youku_error(err) -> bool:
    """True when the message is a known user-content condition, not a bug."""
    msg = str(err)
    return ('China only' in msg) or ('private' in msg) or msg.startswith('Youku server reported error')

Try / catch

try:
    info = ydl.extract_info(url)
except ExtractorError as e:
    if str(e).startswith('Youku server reported error'):
        code = parse_code(str(e))  # log code/note and triage per upstream reason
        handle_upstream(code)
    else:
        raise

Prevention

When it happens

Trigger: Any call to https://ups.youku.com/ups/get.json that returns data.error with a code/note outside the two known patterns: deleted videos, region blocks with different wording, expired links, anti-crawler/rate-limit responses, or API changes that shift note text.

Common situations: Deleted or taken-down videos; Youku A/B wording changes in the error note; ccb params or headers (basic_data_params/headers) becoming stale after an API revision so the server rejects the request; running from datacenter IPs that Youku throttles.

Related errors


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