ytdl-org/youtube-dl · error · ExtractorError

%s returned error: %s

Error message

%s returned error: %s

What it means

Raised by TvigleIE when the cloud.tvigle.ru API returns a playlist item with an errorMessage and no 'videos' dict, i.e. the server explicitly reported a playback error for that video id. Geo-blocked cases are routed separately to raise_geo_restricted; this branch covers all other server-side refusals (removed, restricted by age, etc.). Marked expected=True so it is surfaced as a normal failure, not a crash.

Source

Thrown at youtube_dl/extractor/tvigle.py:82

                (r'<div[^>]+class=["\']player["\'][^>]+id=["\'](\d+)',
                 r'cloudId\s*=\s*["\'](\d+)',
                 r'class="video-preview current_playing" id="(\d+)"'),
                webpage, 'video id')

        video_data = self._download_json(
            'http://cloud.tvigle.ru/api/play/video/%s/' % video_id, display_id)

        item = video_data['playlist']['items'][0]

        videos = item.get('videos')

        error_message = item.get('errorMessage')
        if not videos and error_message:
            if item.get('isGeoBlocked') is True:
                self.raise_geo_restricted(
                    msg=error_message, countries=self._GEO_COUNTRIES)
            else:
                raise ExtractorError(
                    '%s returned error: %s' % (self.IE_NAME, error_message),
                    expected=True)

        title = item['title']
        description = item.get('description')
        thumbnail = item.get('thumbnail')
        duration = float_or_none(item.get('durationMilliseconds'), 1000)
        age_limit = parse_age_limit(item.get('ageRestrictions'))

        formats = []
        for vcodec, url_or_fmts in item['videos'].items():
            if vcodec == 'hls':
                m3u8_url = url_or_none(url_or_fmts)
                if not m3u8_url:
                    continue
                formats.extend(self._extract_m3u8_formats(
                    m3u8_url, video_id, ext='mp4', entry_protocol='m3u8_native',
                    m3u8_id='hls', fatal=False))

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Open the video page at tvigle.ru in a browser to confirm the video still exists and is playable in your region.
  2. If the page shows a regional restriction, use a VPN/Russian IP; the geo path is separate but the server may fold both into errorMessage.
  3. Find the video on the official tvigle.ru site and copy a fresh URL (old IDs may be dead).
  4. Update to a newer youtube-dl/yt-dlp build in case the API contract changed.
Defensive patterns

Strategy: try-catch

Validate before calling

import requests
r = requests.get('http://cloud.tvigle.ru/api/play/video/%s/' % video_id)
item = r.json()['playlist']['items'][0]
if not item.get('videos') and item.get('errorMessage'):
    skip(video_id, reason=item['errorMessage'])

Type guard

def tvigle_unavailable(item: dict) -> bool:
    return not item.get('videos') and bool(item.get('errorMessage'))

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'returned error:' in str(e) or 'geo' in str(e).lower():
        mark_unavailable(url, str(e))
    else:
        raise

Prevention

When it happens

Trigger: GET http://cloud.tvigle.ru/api/play/video/<id>/ returns items[0] with errorMessage set (e.g. 'Video is deleted' or a Russian-language refusal) and item['videos'] empty/absent, while isGeoBlocked is not True.

Common situations: Video removed from tvigle.ru catalog, content taken down for rights reasons, region issues that the API does not flag as geo-block, stale video IDs from old links.

Related errors


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