{"record":{"id":"d7499017734e06f6","repo":"ytdl-org/youtube-dl","slug":"an-extractor-error-has-occurred","errorCode":null,"errorMessage":"An extractor error has occurred.","messagePattern":"An extractor error has occurred\\.","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/common.py","lineNumber":587,"sourceCode":"        \"\"\"Extracts URL information and returns it in list of dicts.\"\"\"\n        try:\n            for _ in range(2):\n                try:\n                    self.initialize()\n                    ie_result = self._real_extract(url)\n                    if self._x_forwarded_for_ip:\n                        ie_result['__x_forwarded_for_ip'] = self._x_forwarded_for_ip\n                    return ie_result\n                except GeoRestrictedError as e:\n                    if self.__maybe_fake_ip_and_retry(e.countries):\n                        continue\n                    raise\n        except ExtractorError:\n            raise\n        except compat_http_client.IncompleteRead as e:\n            raise ExtractorError('A network error has occurred.', cause=e, expected=True)\n        except (KeyError, StopIteration) as e:\n            raise ExtractorError('An extractor error has occurred.', cause=e)\n\n    def __maybe_fake_ip_and_retry(self, countries):\n        if (not self.get_param('geo_bypass_country', None)\n                and self._GEO_BYPASS\n                and self.get_param('geo_bypass', True)\n                and not self._x_forwarded_for_ip\n                and countries):\n            country_code = random.choice(countries)\n            self._x_forwarded_for_ip = GeoUtils.random_ipv4(country_code)\n            if self._x_forwarded_for_ip:\n                self.report_warning(\n                    'Video is geo restricted. Retrying extraction with fake IP %s (%s) as X-Forwarded-For.'\n                    % (self._x_forwarded_for_ip, country_code.upper()))\n                return True\n        return False\n\n    def set_downloader(self, downloader):\n        \"\"\"Sets the downloader for this IE.\"\"\"","sourceCodeStart":569,"sourceCodeEnd":605,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/common.py#L569-L605","documentation":"Raised by InfoExtractor.extract when _real_extract dies with an uncaught KeyError or StopIteration. These two exception types are treated as 'extractor looked up a key/next() that does not exist' — i.e. the page's data did not match what the extractor expected. It is NOT marked expected: it signals a broken or outdated extractor, and the original traceback is attached as cause.","triggerScenarios":"A site changed its JSON keys or HTML structure so a dict['key'] lookup or next(iterator) inside the extractor fails — e.g. renaming 'formats', missing 'url' in an entry, iterating an empty generator. Any site-layout drift manifests here.","commonSituations":"Running an old youtube-dl against redesigned sites (the dominant cause); race where content is served differently (A/B tests, consent pages replacing expected markup).","solutions":["Update youtube-dl (youtube-dl -U) — extractor fixes for site changes land constantly.","If already current, switch to yt-dlp, which is actively maintained.","Reproduce with -v (--verbose) and check the cause traceback to see which lookup failed; report or patch the extractor.","Verify the URL is the right type for the extractor you are hitting (wrong-URL dispatch can trigger the same crash)."],"exampleFix":"# before\ninfo = ydl.extract_info(url)  # KeyError -> 'An extractor error has occurred.'\n\n# after: run verbose to find the failing lookup, then report/patch\nyoutube_dl -v <url>   # traceback shows e.g. KeyError: 'formats'","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"from youtube_dl.utils import ExtractorError\ntry:\n    info = ydl.extract_info(url)\nexcept ExtractorError as e:\n    if not e.expected and isinstance(e.cause, (KeyError, StopIteration)):\n        report_broken_extractor(url, str(e.cause))  # extractor bug, not user error\n    raise","preventionTips":["Keep youtube-dl/yt-dlp updated — KeyError/StopIteration usually means a site changed.","Report the verbose traceback (-v) upstream so extractors get fixed.","Treat non-expected ExtractorErrors as bugs, not as bad input."],"tags":["extractor-bug","keyerror","stopiteration","site-change"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}