{"record":{"id":"cf8b9e55a0ad1eb1","repo":"ytdl-org/youtube-dl","slug":"video-s-is-no-longer-available-cf8b9e","errorCode":null,"errorMessage":"Video %s is no longer available","messagePattern":"Video (.+?) is no longer available","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/vgtv.py","lineNumber":180,"sourceCode":"            'url': 'http://www.vgtv.no/video/84196/hevnen-er-soet-episode-10-abu',\n            'only_matching': True,\n        },\n    ]\n\n    def _real_extract(self, url):\n        mobj = re.match(self._VALID_URL, url)\n        video_id = mobj.group('id')\n        host = mobj.group('host')\n        appname = self._HOST_TO_APPNAME[host] if host else mobj.group('appname')\n        vendor = self._APP_NAME_TO_VENDOR[appname]\n\n        data = self._download_json(\n            'http://svp.vg.no/svp/api/v1/%s/assets/%s?appName=%s-website'\n            % (vendor, video_id, appname),\n            video_id, 'Downloading media JSON')\n\n        if data.get('status') == 'inactive':\n            raise ExtractorError(\n                'Video %s is no longer available' % video_id, expected=True)\n\n        info = {\n            'formats': [],\n        }\n        if len(video_id) == 5:\n            if appname == 'bttv':\n                info = self._extract_video_info('btno', video_id)\n\n        streams = data['streamUrls']\n        stream_type = data.get('streamType')\n        is_live = stream_type == 'live'\n        formats = []\n\n        hls_url = streams.get('hls')\n        if hls_url:\n            formats.extend(self._extract_m3u8_formats(\n                hls_url, video_id, 'mp4',","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/vgtv.py#L162-L198","documentation":"Raised by the VGTV extractor (and its sibling hosts via _HOST_TO_APPNAME) when the svp.vg.no asset JSON reports status == 'inactive'. That is the platform's own flag for retired/unpublished assets, so the message is a faithful content-state report. expected=True.","triggerScenarios":"Extracting a vg.no/vgtv.no/bttv/abgtv URL whose SVP API asset (vendor path /assets/<id>?appName=...) has data['status'] == 'inactive'.","commonSituations":"News clips taken down after rights expired (very common for NRK/Schibsted sports highlights); articles deleted; short 5-char ids routed to the btno path that no longer resolves.","solutions":["Open the article in a browser — if the player says the video is unavailable, it is gone.","Search the publisher's site for a re-published version of the clip and use that URL.","If the video plays in a browser but the API says inactive, the appName/vendor mapping changed — verify _HOST_TO_APPNAME/_APP_NAME_TO_VENDOR and the appName=<x>-website query parameter.","Treat as terminal: skip, do not retry."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import json, urllib.request\napi = 'http://svp.vg.no/svp/api/v1/%s/assets/%s?appName=%s-website' % (vendor, video_id, appname)\ndata = json.load(urllib.request.urlopen(api))\nif data.get('status') == 'inactive':\n    skip(video_id, 'asset inactive')","typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if e.expected and 'no longer available' in str(e):\n        log_skip(url, str(e))  # rights-expired news clips are permanent\n    else:\n        raise","preventionTips":["Pre-check the SVP asset JSON for status=='inactive' before extracting.","Expect Schibsted news clips to expire with media rights.","Archive expected skips with reasons so re-runs skip them fast."],"tags":["api","content-missing","site-side-rejection","expected-error"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}