ytdl-org/youtube-dl · error · ExtractorError

%s (site code %d)

Error message

%s (site code %d)

What it means

Raised by NetEase Music's format builder when no playable media links were produced AND the returned error code is outside 200-399 — i.e. the site API explicitly errored. The message embeds the numeric site code (e.g. lack of permission or copyright block). For codes inside 200-399 it instead raises a geo-restriction error limited to CN.

Source

Thrown at youtube_dl/extractor/neteasemusic.py:143

                song_url = try_get(song, lambda x: x['url'])
                if not song_url:
                    continue
                if self._is_valid_url(song_url, info['id'], 'song'):
                    formats.append({
                        'url': song_url,
                        'ext': details.get('extension'),
                        'abr': float_or_none(song.get('br'), scale=1000),
                        'format_id': song_format,
                        'filesize': int_or_none(song.get('size')),
                        'asr': int_or_none(details.get('sr')),
                    })
                elif err == 0:
                    err = try_get(song, lambda x: x['code'], int)

        if not formats:
            msg = 'No media links found'
            if err != 0 and (err < 200 or err >= 400):
                raise ExtractorError(
                    '%s (site code %d)' % (msg, err, ), expected=True)
            else:
                self.raise_geo_restricted(
                    msg + ': probably this video is not available from your location due to geo restriction.',
                    countries=['CN'])

        return formats

    @classmethod
    def convert_milliseconds(cls, ms):
        return int(round(ms / 1000.0))

    def query_api(self, endpoint, video_id, note):
        req = sanitized_Request('%s%s' % (self._API_BASE, endpoint))
        req.add_header('Referer', self._API_BASE)
        return self._download_json(req, video_id, note)

View on GitHub (pinned to 956b8c5855)

Solutions

  1. If the code indicates regional unavailability, retry through a mainland-China proxy: --proxy <cn-proxy>.
  2. Look up the numeric site code in NetEase API references to see if it is copyright/login related; if login-gated, pass cookies with --cookies.
  3. Update youtube-dl / yt-dlp if all songs fail uniformly (API change rather than per-song block).

Example fix

# before
youtube-dl 'http://music.163.com/song?id=123456'

# after
youtube-dl --proxy http://cn-proxy:8080 'http://music.163.com/song?id=123456'
Defensive patterns

Strategy: retry

Validate before calling

import requests
r = requests.get('http://music.163.com/api/song/detail', params={'id': song_id}).json()
if not r.get('songs'):
    print('song unavailable — check region/licensing before extracting')

Try / catch

from youtube_dl.utils import ExtractorError, GeoRestrictedError
try:
    ydl.extract_info(url)
except GeoRestrictedError:
    retry_with_proxy(url, region='CN')
except ExtractorError as e:
    if 'site code' in str(e):
        code = int(str(e).rsplit(' ', 1)[-1].rstrip(')'))
        handle_netease_code(code)  # e.g. login-gated vs removed
    else:
        raise

Prevention

When it happens

Trigger: Calling NetEaseCloudMusicIE on a song whose API response yields no formats and err (from the per-format 'code' or song['code']) is non-zero and not in [200,400).

Common situations: Region-locked NetEase catalog entries; songs removed for licensing; the 200-399 branch (e.g. -110 or in-range codes) usually means 'not available from your location', fixed by CN egress.

Related errors


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