ytdl-org/youtube-dl · error · ExtractorError

Video %s does not exist

Error message

Video %s does not exist

What it means

Raised by TwitchVodIE._download_info when the VideoMetadata GraphQL query returns data.video == null, meaning Twitch has no VOD with that id. Expected error with the requested id in the message; distinct from 'sub-only video' errors which other branches handle.

Source

Thrown at youtube_dl/extractor/twitch.py:266

        'only_matching': True,
    }, {
        'url': 'https://player.twitch.tv/?video=480452374',
        'only_matching': True,
    }]

    def _download_info(self, item_id):
        data = self._download_gql(
            item_id, [{
                'operationName': 'VideoMetadata',
                'variables': {
                    'channelLogin': '',
                    'videoID': item_id,
                },
            }],
            'Downloading stream metadata GraphQL')[0]['data']
        video = data.get('video')
        if video is None:
            raise ExtractorError(
                'Video %s does not exist' % item_id, expected=True)
        return self._extract_info_gql(video, item_id)

    @staticmethod
    def _extract_info(info):
        status = info.get('status')
        if status == 'recording':
            is_live = True
        elif status == 'recorded':
            is_live = False
        else:
            is_live = None
        _QUALITIES = ('small', 'medium', 'large')
        quality_key = qualities(_QUALITIES)
        thumbnails = []
        preview = info.get('preview')
        if isinstance(preview, dict):
            for thumbnail_id, thumbnail_url in preview.items():

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Open the VOD URL in a browser to confirm it still exists.
  2. If deleted, look for a re-upload or clip of the same broadcast.
  3. For sub-only VODs, authenticate with --cookies from a subscribed browser session.
  4. Update to yt-dlp for current Twitch GraphQL handling (and workaround for deleted-while-listed VODs).
Defensive patterns

Strategy: validation

Validate before calling

import requests
q = [{'operationName': 'VideoMetadata', 'variables': {'channelLogin': '', 'videoID': vod_id}}]
r = requests.post('https://gql.twitch.tv/gql', json=q, headers={'Client-ID': CLIENT_ID})
if r.json()[0]['data'].get('video') is None:
    skip(vod_id, 'VOD does not exist')

Type guard

def vod_exists(data: dict) -> bool:
    return data.get('video') is not None

Try / catch

try:
    ydl.extract_info(vod_url)
except ExtractorError as e:
    if 'does not exist' in str(e):
        mark_deleted(vod_id)
    else:
        raise

Prevention

When it happens

Trigger: Running the VideoMetadata operation with videoID <item_id> where the id does not exist — deleted VODs, expired past-broadcasts (Twitch deletes most after ~60 days), mistyped ids, or VODs hidden by the channel.

Common situations: Old broadcast links whose VOD retention window elapsed, channel-deleted highlights, sub-only VODs sometimes also surface here, ids scraped from stale pages.

Related errors


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