{"record":{"id":"ed9fb9d70d5bbc08","repo":"ytdl-org/youtube-dl","slug":"s-said-s-ed9fb9","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/litv.py","lineNumber":124,"sourceCode":"            r'uiHlsUrl\\s*=\\s*testBackendData\\(([^;]+)\\);',\n            webpage, 'video data', default='{}'), video_id)\n        if not video_data:\n            payload = {\n                'assetId': program_info['assetId'],\n                'watchDevices': program_info['watchDevices'],\n                'contentType': program_info['contentType'],\n            }\n            video_data = self._download_json(\n                'https://www.litv.tv/vod/getMainUrl', video_id,\n                data=json.dumps(payload).encode('utf-8'),\n                headers={'Content-Type': 'application/json'})\n\n        if not video_data.get('fullpath'):\n            error_msg = video_data.get('errorMessage')\n            if error_msg == 'vod.error.outsideregionerror':\n                self.raise_geo_restricted('This video is available in Taiwan only')\n            if error_msg:\n                raise ExtractorError('%s said: %s' % (self.IE_NAME, error_msg), expected=True)\n            raise ExtractorError('Unexpected result from %s' % self.IE_NAME)\n\n        formats = self._extract_m3u8_formats(\n            video_data['fullpath'], video_id, ext='mp4',\n            entry_protocol='m3u8_native', m3u8_id='hls')\n        for a_format in formats:\n            # LiTV HLS segments doesn't like compressions\n            a_format.setdefault('http_headers', {})['Youtubedl-no-compression'] = True\n\n        title = program_info['title'] + program_info.get('secondaryMark', '')\n        description = program_info.get('description')\n        thumbnail = program_info.get('imageFile')\n        categories = [item['name'] for item in program_info.get('category', [])]\n        episode = int_or_none(program_info.get('episode'))\n\n        return {\n            'id': video_id,\n            'formats': formats,","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/litv.py#L106-L142","documentation":"Thrown by the LiTV extractor when the vod/getMainUrl API call succeeds HTTP-wise but the returned JSON lacks a 'fullpath' key and instead carries an 'errorMessage'. It is marked expected=True, meaning it represents a normal, user-facing service refusal (e.g. expired asset, member-only content) rather than a bug in youtube-dl. The '%s said: %s' pattern prefixes the extractor name (LiTV) with the raw service message so the user sees exactly what the provider replied.","triggerScenarios":"POST to https://www.litv.tv/vod/getMainUrl with the contentType payload returns JSON without 'fullpath' but with a non-empty 'errorMessage'. Any errorMessage other than 'vod.error.outsideregionerror' (which is converted to a geo-restriction error just above) reaches this raise.","commonSituations":"Requesting a drama/episode that is no longer licensed, member-only content without a subscription cookie, or a video_id that LiTV no longer serves. Also hit when LiTV changes its API response shape so 'fullpath' is renamed, leaving only an error field.","solutions":["Read the embedded service message; it is LiTV's own text and names the exact refusal reason (expired, member-only, removed).","If the message indicates region blocking, supply a Taiwan IP/proxy via --proxy or --geo-verification-proxy instead of retrying directly.","If content is member-only, log in with the appropriate account cookies (--add-header 'Cookie: ...').","If the message looks like a schema change (unrecognized text), report the video URL to the youtube-dl issue tracker so the LiTV extractor can be updated."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def is_litv_error_payload(video_data):\n    return isinstance(video_data, dict) and not video_data.get('fullpath') and bool(video_data.get('errorMessage'))","tryCatchPattern":"try:\n    info = ydl.extract_info(url, download=False)\nexcept ExtractorError as e:\n    if 'LiTV said:' in str(e):\n        reason = str(e).split('said:', 1)[1].strip()  # service's own message; act on it (geo, membership, expiry)\n    else:\n        raise","preventionTips":["Pre-check video availability in a Taiwan-located browser session before batching.","Keep account cookies current when downloading member-only LiTV content.","Wrap batch jobs to record the embedded service message per id instead of aborting the whole run."],"tags":["extractor","api-response","expected-error","streaming"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}