{"record":{"id":"f3fea2ff2c0f15c3","repo":"ytdl-org/youtube-dl","slug":"s-f3fea2","errorCode":null,"errorMessage":"%s","messagePattern":"%s","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/stitcher.py","lineNumber":25,"sourceCode":"    clean_podcast_url,\n    ExtractorError,\n    int_or_none,\n    str_or_none,\n    try_get,\n    url_or_none,\n)\n\n\nclass StitcherBaseIE(InfoExtractor):\n    _VALID_URL_BASE = r'https?://(?:www\\.)?stitcher\\.com/(?:podcast|show)/'\n\n    def _call_api(self, path, video_id, query):\n        resp = self._download_json(\n            'https://api.prod.stitcher.com/' + path,\n            video_id, query=query)\n        error_massage = try_get(resp, lambda x: x['errors'][0]['message'])\n        if error_massage:\n            raise ExtractorError(error_massage, expected=True)\n        return resp['data']\n\n    def _extract_description(self, data):\n        return clean_html(data.get('html_description') or data.get('description'))\n\n    def _extract_audio_url(self, episode):\n        return url_or_none(episode.get('audio_url') or episode.get('guid'))\n\n    def _extract_show_info(self, show):\n        return {\n            'thumbnail': show.get('image_base_url'),\n            'series': show.get('title'),\n        }\n\n    def _extract_episode(self, episode, audio_url, show_info):\n        info = {\n            'id': compat_str(episode['id']),\n            'display_id': episode.get('slug'),","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/stitcher.py#L7-L43","documentation":"Raised by StitcherShowIE/StitcherBaseIE._call_api when a call to api.prod.stitcher.com returns a JSON body whose errors[0].message field is non-empty; the API error text is re-raised verbatim as an ExtractorError (expected=True). The variable is misspelled 'error_massage' in the source but the behavior is plain error passthrough.","triggerScenarios":"Any _download_json request to https://api.prod.stitcher.com/<path> (show feed, episode) where the response contains a non-null errors[0].message — e.g. unknown show id, removed episode, or geoblock reported by the API.","commonSituations":"Podcast/episode removed from Stitcher; URL with an old or wrong id; Stitcher API schema changed so formerly-valid ids now return errors; SiriusXM shutdown of Stitcher content.","solutions":["Read the exact API message embedded in the ExtractorError — it is Stitcher's own reason (not found, removed, etc.) and dictates the fix.","Verify the show/episode URL on stitcher.com and re-copy it; ids in URLs drift when shows are renamed.","Upgrade youtube-dl/yt-dlp; Stitcher API changes are handled upstream.","If the podcast left Stitcher, find its RSS feed (often listed on the show's site) and download episodes from the feed directly."],"exampleFix":"// before: caller treats every failure as a network bug\n// after: surface the API's own message\ntry {\n  info = ydl.extractInfo(url, {download: false});\n} catch (e) {\n  if (e.message.includes('said') === false) throw e; // not applicable here\n}\n// Python:\ntry:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if e.expected:\n        print('Stitcher API said:', str(e))  # passthrough of errors[0].message","handlingStrategy":"try-catch","validationCode":"# Optional: hit the Stitcher API yourself first to validate the id\nimport json, urllib.request\nresp = json.load(urllib.request.urlopen('https://api.prod.stitcher.com/shows/%s/episodes' % show_id))\nif resp.get('errors'):\n    print('API refused:', resp['errors'][0]['message'])","typeGuard":null,"tryCatchPattern":"try:\n    info = ydl.extract_info(url)\nexcept ExtractorError as e:\n    if e.expected:\n        log.warning('Stitcher API said: %s', str(e))  # site's own message\n        return None\n    raise","preventionTips":["Treat the raised text as authoritative — it is Stitcher's own errors[0].message.","Verify show/episode URLs on stitcher.com before batch jobs.","Stitcher content has been winding down; keep a podcast RSS fallback."],"tags":["api-error","passthrough","podcast","expected-error"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}