{"record":{"id":"b6989d9d6bca49e5","repo":"yt-dlp/yt-dlp","slug":"ie-name-returned-error-error","errorCode":null,"errorMessage":"{IE_NAME} returned error: {error}","messagePattern":"(.+?) returned error: (.+?)","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/ustream.py","lineNumber":181,"sourceCode":"            video_id = m.group('id')\n            desktop_url = 'http://www.ustream.tv/recorded/' + video_id\n            return self.url_result(desktop_url, 'Ustream')\n        if m.group('type') == 'embed':\n            video_id = m.group('id')\n            webpage = self._download_webpage(url, video_id)\n            content_video_ids = self._parse_json(self._search_regex(\n                r'ustream\\.vars\\.offAirContentVideoIds=([^;]+);', webpage,\n                'content video IDs'), video_id)\n            return self.playlist_result(\n                (self.url_result('http://www.ustream.tv/recorded/' + u, 'Ustream') for u in content_video_ids),\n                video_id)\n\n        params = self._download_json(\n            f'https://api.ustream.tv/videos/{video_id}.json', video_id)\n\n        error = params.get('error')\n        if error:\n            raise ExtractorError(\n                f'{self.IE_NAME} returned error: {error}', expected=True)\n\n        video = params['video']\n\n        title = video['title']\n        filesize = float_or_none(video.get('file_size'))\n\n        formats = [{\n            'id': video_id,\n            'url': video_url,\n            'ext': format_id,\n            'filesize': filesize,\n        } for format_id, video_url in video['media_urls'].items() if video_url]\n\n        if not formats:\n            hls_streams = self._get_streams(url, video_id, app_id_ver=(11, 2))\n            if hls_streams:\n                # m3u8_native leads to intermittent ContentTooShortError","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/ustream.py#L163-L199","documentation":"Raised by UstreamIE._real_extract when the JSON from api.ustream.tv/videos/<id>.json contains a non-empty 'error' key; the API's own error text (e.g. 'not found') is appended to the message. The HTTP layer may still return 200 here, so this is the extractor's application-level check after a successful download. Expected=True.","triggerScenarios":"Extracting a ustream.tv/recorded/<id> (or IBM Video Streaming) URL whose API responds with an error object — deleted recordings, private videos, or invalid ids.","commonSituations":"Old recorded URLs after Ustream's IBM migration removed content; deleted or unlisted recordings; mistyped numeric ids; playlists referencing dead recordings.","solutions":["Open the URL in a browser to confirm the recording still exists and is public","If the channel is live, use the live URL form instead of /recorded/<id>","Remove dead ids from automated queues and log them instead of retrying","Update yt-dlp in case the API endpoint moved after platform changes"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def is_ustream_api_error(e: Exception) -> bool:\n    return isinstance(e, ExtractorError) and 'Ustream returned error' in str(e)","tryCatchPattern":"try:\n    ydl.extract_info(url, download=True)\nexcept ExtractorError as e:\n    if 'Ustream returned error' in str(e):\n        archive_dead_recording(video_id)  # API-level rejection is terminal\n    else:\n        raise","preventionTips":["Treat API error payloads as permanent: remove the id from queues instead of retrying","Validate that /recorded/<id> pages still exist in a browser before batch runs"],"tags":["ustream","api-error","video-deleted","expected-error"],"backgroundTag":"api-error-response","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}