{"record":{"id":"e2ba2e6d3073fb1f","repo":"ytdl-org/youtube-dl","slug":"s-said-s-e2ba2e","errorCode":null,"errorMessage":"%s said: %s","messagePattern":"%s said: %s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/pbs.py","lineNumber":617,"sourceCode":"                        })\n\n        formats = []\n        http_url = None\n        for num, redirect in enumerate(redirects):\n            redirect_id = redirect.get('eeid')\n\n            redirect_info = self._download_json(\n                '%s?format=json' % redirect['url'], display_id,\n                'Downloading %s video url info' % (redirect_id or num),\n                headers=self.geo_verification_headers())\n\n            if redirect_info['status'] == 'error':\n                message = self._ERRORS.get(\n                    redirect_info['http_code'], redirect_info['message'])\n                if redirect_info['http_code'] == 403:\n                    self.raise_geo_restricted(\n                        msg=message, countries=self._GEO_COUNTRIES)\n                raise ExtractorError(\n                    '%s said: %s' % (self.IE_NAME, message), expected=True)\n\n            format_url = redirect_info.get('url')\n            if not format_url:\n                continue\n\n            if determine_ext(format_url) == 'm3u8':\n                formats.extend(self._extract_m3u8_formats(\n                    format_url, display_id, 'mp4', m3u8_id='hls', fatal=False))\n            else:\n                formats.append({\n                    'url': format_url,\n                    'format_id': redirect_id,\n                })\n                if re.search(r'^https?://.*(?:\\d+k|baseline)', format_url):\n                    http_url = format_url\n        self._remove_duplicate_formats(formats)\n        m3u8_formats = list(filter(","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/pbs.py#L599-L635","documentation":"Raised inside PBS's redirect-handling loop when a video redirect's JSON info returns status 'error'. The message interpolates the extractor name and either a mapped message for the http_code (from _ERRORS) or the server's own message. A 403 is diverted to raise_geo_restricted first, so this raise covers other HTTP codes.","triggerScenarios":"Extracting a PBS video where one of its 'redirect' sources (PBS Media Manager partners) returns {'status': 'error', 'http_code': N}. Typical codes: 404 (partner removed the asset), 403 handled separately as geo-block, or partner-specific errors mapped in _ERRORS.","commonSituations":"PBS partner stations pulling content after broadcast rights expire; regional member-station content unavailable outside the US; a single broken redirect in a multi-part video where other parts still work.","solutions":["Try the video on pbs.org in a browser to confirm it still streams; if removed, use the station's own site","For non-403 errors outside the US, still test with a US IP/VPN since PBS availability is US-centric","If only one part fails, extract remaining parts individually by their segment URLs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    info = ydl.extract_info(url)\nexcept GeoRestrictedError:\n    print('PBS blocked this video regionally')\nexcept ExtractorError as e:\n    if e.expected and 'said:' in str(e):\n        print('PBS partner error:', str(e))","preventionTips":["Catch GeoRestrictedError separately from generic ExtractorError","Treat per-part failures as partial results; keep going with remaining segments","Verify US availability for member-station content"],"tags":["pbs","api-error","geo","content-gone","extractor-error","expected"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}