{"record":{"id":"c9d8f7536365073d","repo":"ytdl-org/youtube-dl","slug":"video-s-does-not-exist-c9d8f7","errorCode":null,"errorMessage":"Video %s does not exist","messagePattern":"Video (.+?) does not exist","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/twitch.py","lineNumber":266,"sourceCode":"        'only_matching': True,\n    }, {\n        'url': 'https://player.twitch.tv/?video=480452374',\n        'only_matching': True,\n    }]\n\n    def _download_info(self, item_id):\n        data = self._download_gql(\n            item_id, [{\n                'operationName': 'VideoMetadata',\n                'variables': {\n                    'channelLogin': '',\n                    'videoID': item_id,\n                },\n            }],\n            'Downloading stream metadata GraphQL')[0]['data']\n        video = data.get('video')\n        if video is None:\n            raise ExtractorError(\n                'Video %s does not exist' % item_id, expected=True)\n        return self._extract_info_gql(video, item_id)\n\n    @staticmethod\n    def _extract_info(info):\n        status = info.get('status')\n        if status == 'recording':\n            is_live = True\n        elif status == 'recorded':\n            is_live = False\n        else:\n            is_live = None\n        _QUALITIES = ('small', 'medium', 'large')\n        quality_key = qualities(_QUALITIES)\n        thumbnails = []\n        preview = info.get('preview')\n        if isinstance(preview, dict):\n            for thumbnail_id, thumbnail_url in preview.items():","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/twitch.py#L248-L284","documentation":"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.","triggerScenarios":"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.","commonSituations":"Old broadcast links whose VOD retention window elapsed, channel-deleted highlights, sub-only VODs sometimes also surface here, ids scraped from stale pages.","solutions":["Open the VOD URL in a browser to confirm it still exists.","If deleted, look for a re-upload or clip of the same broadcast.","For sub-only VODs, authenticate with --cookies from a subscribed browser session.","Update to yt-dlp for current Twitch GraphQL handling (and workaround for deleted-while-listed VODs)."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import requests\nq = [{'operationName': 'VideoMetadata', 'variables': {'channelLogin': '', 'videoID': vod_id}}]\nr = requests.post('https://gql.twitch.tv/gql', json=q, headers={'Client-ID': CLIENT_ID})\nif r.json()[0]['data'].get('video') is None:\n    skip(vod_id, 'VOD does not exist')","typeGuard":"def vod_exists(data: dict) -> bool:\n    return data.get('video') is not None","tryCatchPattern":"try:\n    ydl.extract_info(vod_url)\nexcept ExtractorError as e:\n    if 'does not exist' in str(e):\n        mark_deleted(vod_id)\n    else:\n        raise","preventionTips":["Remember Twitch deletes most VODs after ~60 days; archive promptly.","Check VOD existence via one lightweight GraphQL call before queueing downloads."],"tags":["twitch","vod","not-found","availability"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}