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

Code before:
                headers['x-guest-token'] = self._TOKENS[bearer_token]

            try:
                allowed_status = {400, 403, 404} if graphql else {403}
                result = self._download_json(
                    (self._GRAPHQL_API_BASE if graphql else self._API_BASE) + path,
                    video_id, headers=headers, query=query, expected_status=allowed_status)
                break

            except ExtractorError as e:
                if error:
                    raise error

                if not isinstance(e.cause, urllib.error.HTTPError) or e.cause.code != 404:
                    raise

                error = e
                self.report_warning(
                    'Twitter API gave 404 response, retrying with deprecated token. '
                    'This means only one media item can be extracted.')

        errors = traverse_obj(result, 'errors')
        if errors:
            error_message = ', '.join(set(traverse_obj(errors, (..., 'message'), expected_type=str)))
            if not error_message:
                error_message = 'Unknown error.'
            raise ExtractorError(f'Error(s) while querying api: {error_message}', expected=True)

        assert result is not None
        return result

    def _build_graphql_query(self, media_id):
        raise NotImplementedError('Method must be implemented to support GraphQL')

    def _call_graphql_api(self, endpoint, media_id):
        data = self._build_graphql_query(media_id)
        query = {key: json.dumps(value, separators=(',', ':')) for key, value in data.items()}
        return traverse_obj(self._call_api(endpoint, media_id, query=query, graphql=True), 'data')


class TwitterCardIE(InfoExtractor):
    IE_NAME = 'twitter:card'
    _VALID_URL = TwitterBaseIE._BASE_REGEX + r'i/(?:cards/tfw/v1|videos(?:/tweet)?)/(?P<id>\d+)'
    _TESTS = [
        {
            'url': 'https://twitter.com/i/cards/tfw/v1/560070183650213889',
            # MD5 checksums are different in different places
            'info_dict': {
                'id': '560070183650213889',
                'ext': 'mp4',
                'title': "Twitter - You can now shoot, edit and share video on Twitter. Capture life's most moving moments from your perspective.",

Review comment (suggestion):
```suggestion
        if result.get('errors'):
            error_message = ', '.join(set(traverse_obj(
                result, ('errors', ..., 'message'), expected_type=str))) or 'Unknown error'
```

Code after:

            try:
                allowed_status = {400, 403, 404} if graphql else {403}
                result = self._download_json(
                    (self._GRAPHQL_API_BASE if graphql else self._API_BASE) + path,
                    video_id, headers=headers, query=query, expected_status=allowed_status)
                break

            except ExtractorError as e:
                if last_error:
                    raise last_error
                elif not isinstance(e.cause, urllib.error.HTTPError) or e.cause.code != 404:
                    raise
                last_error = e
                self.report_warning(
                    'Twitter API gave 404 response, retrying with deprecated token. '
                    'Only one media item can be extracted')

        if result.get('errors'):
            error_message = ', '.join(set(traverse_obj(
                result, ('errors', ..., 'message'), expected_type=str))) or 'Unknown error'
            raise ExtractorError(f'Error(s) while querying api: {error_message}', expected=True)

        assert result is not None
        return result

    def _build_graphql_query(self, media_id):
        raise NotImplementedError('Method must be implemented to support GraphQL')

    def _call_graphql_api(self, endpoint, media_id):
        data = self._build_graphql_query(media_id)
        query = {key: json.dumps(value, separators=(',', ':')) for key, value in data.items()}
        return traverse_obj(self._call_api(endpoint, media_id, query=query, graphql=True), 'data')


class TwitterCardIE(InfoExtractor):
    IE_NAME = 'twitter:card'
    _VALID_URL = TwitterBaseIE._BASE_REGEX + r'i/(?:cards/tfw/v1|videos(?:/tweet)?)/(?P<id>\d+)'
    _TESTS = [
        {
            'url': 'https://twitter.com/i/cards/tfw/v1/560070183650213889',
            # MD5 checksums are different in different places
            'info_dict': {
                'id': '560070131976392705',
                'ext': 'mp4',
                'title': "Twitter - You can now shoot, edit and share video on Twitter. Capture life's most moving moments from your perspective.",
                'description': 'md5:18d3e24bb4f6e5007487dd546e53bd96',
                'uploader': 'Twitter',
                'uploader_id': 'Twitter',
                'thumbnail': r're:^https?://.*\.jpg',
                'duration': 30.033,