{"record":{"id":"47b5005e2fcc2f3f","repo":"yt-dlp/yt-dlp","slug":"the-vod-does-not-exist","errorCode":null,"errorMessage":"The VOD does not exist","messagePattern":"The VOD does not exist","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/afreecatv.py","lineNumber":183,"sourceCode":"    def _real_extract(self, url):\n        video_id = self._match_id(url)\n        data = self._call_api(\n            'station/video/a/view', video_id, headers={'Referer': url},\n            data=urlencode_postdata({\n                'nTitleNo': video_id,\n                'nApiLevel': 10,\n            }))['data']\n\n        initial_refresh_time = 0\n        strm_id = None\n        # For subscriber-only VODs, we need to call private_auth.php to get CloudFront cookies\n        needs_private_auth = traverse_obj(data, ('sub_upload_type', {str}))\n        if needs_private_auth:\n            strm_id = traverse_obj(data, ('bj_id', {str}, {require('stream ID')}))\n\n        error_code = traverse_obj(data, ('code', {int}))\n        if error_code == -6221:\n            raise ExtractorError('The VOD does not exist', expected=True)\n        elif error_code == -6205:\n            raise ExtractorError('This VOD is private', expected=True)\n\n        common_info = traverse_obj(data, {\n            'title': ('title', {str}),\n            'uploader': ('writer_nick', {str}),\n            'uploader_id': ('bj_id', {str}),\n            'duration': ('total_file_duration', {int_or_none(scale=1000)}),\n            'thumbnails': ('thumb', {self._fixup_thumb}),\n        })\n\n        entries = []\n        for file_num, file_element in enumerate(\n                traverse_obj(data, ('files', lambda _, v: url_or_none(v['file']))), start=1):\n            file_url = file_element['file']\n            if determine_ext(file_url) == 'm3u8':\n                if needs_private_auth:\n                    self._request_webpage(","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/afreecatv.py#L165-L201","documentation":"Soop/AfreecaTV VOD extractor checks the info API's code field; -6221 means the VOD (replay) does not exist -- deleted by the broadcaster, or the title/file number in the URL is invalid. Raised expected=True, so it is reported as a normal unavailability, not a bug.","triggerScenarios":"Extracting a vod.sooplive.com/player/<nno> URL whose numeric id was deleted, mistyped, or never existed; the API returns data with code == -6221.","commonSituations":"Broadcasters delete replays regularly; stale links from forums/search results; hand-edited numeric ids.","solutions":["Open the URL in a browser to confirm the VOD is gone","Browse the uploader's VOD list on sooplive to find a re-upload or the correct id","Drop the dead link from your queue"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from yt_dlp import YoutubeDL\nfrom yt_dlp.utils import DownloadError\n\ntry:\n    info = YoutubeDL().extract_info(url)\nexcept DownloadError as e:\n    if 'The VOD does not exist' in str(e):\n        mark_deleted(url)  # prune dead link, do not retry\n    else:\n        raise","preventionTips":["Validate vod.sooplive.com links in a browser before batch-queuing","Expect broadcasters to delete replays; make deletion a normal path in download queues"],"tags":["afreecatv","soop","vod","deleted"],"backgroundTag":"content-deleted","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}