Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/youtube.py (Python)

Code before:
    def _extract_response(self, item_id, query, note='Downloading API JSON', headers=None,
                          ytcfg=None, check_get_keys=None, ep='browse', fatal=True, api_hostname=None,
                          default_client='web'):
        response = None
        last_error = None
        count = -1
        retries = self.get_param('extractor_retries', 3)
        if check_get_keys is None:
            check_get_keys = []
        while count < retries:
            count += 1
            if last_error:
                self.report_warning('%s. Retrying ...' % last_error)
            try:
                response = self._call_api(
                    ep=ep, fatal=True, headers=headers,
                    video_id=item_id, query=query,
                    context=self._extract_context(ytcfg, default_client),
                    api_key=self._extract_api_key(ytcfg, default_client),
                    api_hostname=api_hostname, default_client=default_client,
                    note='%s%s' % (note, ' (retry #%d)' % count if count else ''))
            except ExtractorError as e:
                if isinstance(e.cause, network_exceptions):
                    # Downloading page may result in intermittent 5xx HTTP error
                    # Sometimes a 404 is also recieved. See: https://github.com/ytdl-org/youtube-dl/issues/28289
                    # We also want to catch all other network exceptions since errors in later pages can be troublesome
                    # See https://github.com/yt-dlp/yt-dlp/issues/507#issuecomment-880188210
                    if not isinstance(e.cause, compat_HTTPError) or e.cause.code not in (403, 429):
                        last_error = error_to_compat_str(e.cause or e)
                        if count < retries:
                            continue
                if fatal:
                    raise
                else:
                    self.report_warning(error_to_compat_str(e))
                    return

            else:
                # Youtube may send alerts if there was an issue with the continuation page
                try:
                    self._extract_and_report_alerts(response, expected=False)
                except ExtractorError as e:
                    if fatal:
                        raise
                    self.report_warning(error_to_compat_str(e))
                    return
                if not check_get_keys or dict_get(response, check_get_keys):
                    break
                # Youtube sometimes sends incomplete data
                # See: https://github.com/ytdl-org/youtube-dl/issues/28194
                last_error = 'Incomplete data received'

Review comment (suggestion):
Sometimes the API errors may return a HTML page (e.g. dead endpoint).
`_parse_json` has no way of silently reporting the error, so this is another way I thought of.

Code after:

    def _extract_response(self, item_id, query, note='Downloading API JSON', headers=None,
                          ytcfg=None, check_get_keys=None, ep='browse', fatal=True, api_hostname=None,
                          default_client='web'):
        response = None
        last_error = None
        count = -1
        retries = self.get_param('extractor_retries', 3)
        if check_get_keys is None:
            check_get_keys = []
        while count < retries:
            count += 1
            if last_error:
                self.report_warning('%s. Retrying ...' % last_error)
            try:
                response = self._call_api(
                    ep=ep, fatal=True, headers=headers,
                    video_id=item_id, query=query,
                    context=self._extract_context(ytcfg, default_client),
                    api_key=self._extract_api_key(ytcfg, default_client),
                    api_hostname=api_hostname, default_client=default_client,
                    note='%s%s' % (note, ' (retry #%d)' % count if count else ''))
            except ExtractorError as e:
                if isinstance(e.cause, network_exceptions):
                    if isinstance(e.cause, compat_HTTPError) and not is_html(e.cause.read(512)):
                        e.cause.seek(0)
                        yt_error = try_get(
                            self._parse_json(e.cause.read().decode(), item_id, fatal=False),
                            lambda x: x['error']['message'], compat_str)
                        if yt_error:
                            self._report_alerts([('ERROR', yt_error)], fatal=False)
                    # Downloading page may result in intermittent 5xx HTTP error
                    # Sometimes a 404 is also recieved. See: https://github.com/ytdl-org/youtube-dl/issues/28289
                    # We also want to catch all other network exceptions since errors in later pages can be troublesome
                    # See https://github.com/yt-dlp/yt-dlp/issues/507#issuecomment-880188210
                    if not isinstance(e.cause, compat_HTTPError) or e.cause.code not in (403, 429):
                        last_error = error_to_compat_str(e.cause or e)
                        if count < retries:
                            continue
                if fatal:
                    raise
                else:
                    self.report_warning(error_to_compat_str(e))
                    return

            else:
                # Youtube may send alerts if there was an issue with the continuation page
                try:
                    self._extract_and_report_alerts(response, expected=False)
                except ExtractorError as e:
                    if fatal: