ytdl-org/youtube-dl · error · ExtractorError
Login failed, %s said: %r
Error message
Login failed, %s said: %r
What it means
Raised by TennisTVIE._login when the POST to tennistv.com/api/users/v1/login succeeds at HTTP level but the JSON body has a truthy error.errorCode. The API's errorMessage is embedded as 'Login failed, TennisTV said: <message>'. Unlike other login errors here it is NOT marked expected=True, so youtube-dl logs it as a login error with the site's reason.
Source
Thrown at youtube_dl/extractor/tennistv.py:58
'Email': username,
'Password': password,
}
login_json = json.dumps(login_form).encode('utf-8')
headers = {
'content-type': 'application/json',
'Referer': 'https://www.tennistv.com/login',
'Origin': 'https://www.tennistv.com',
}
login_result = self._download_json(
'https://www.tennistv.com/api/users/v1/login', None,
note='Logging in',
errnote='Login failed (wrong password?)',
headers=headers,
data=login_json)
if login_result['error']['errorCode']:
raise ExtractorError('Login failed, %s said: %r' % (self.IE_NAME, login_result['error']['errorMessage']))
if login_result['entitlement'] != 'SUBSCRIBED':
self.report_warning('%s may not be subscribed to %s.' % (username, self.IE_NAME))
self._session_token = login_result['sessionToken']
def _real_initialize(self):
self._login()
def _real_extract(self, url):
video_id = self._match_id(url)
webpage = self._download_webpage(url, video_id)
internal_id = self._search_regex(r'video=([0-9]+)', webpage, 'internal video id')
headers = {
'Origin': 'https://www.tennistv.com',
'authorization': 'ATP %s' % self._session_token,View on GitHub (pinned to 956b8c5855)
Solutions
- Read the relayed errorMessage — it is TennisTV's exact refusal reason; fix credentials accordingly.
- Verify sign-in at https://www.tennistv.com/login in a browser before blaming the tool.
- Confirm your subscription is active; a lapsed subscription can produce API-level login errors.
- If credentials are right but it still fails, the API schema likely changed — upgrade youtube-dl/yt-dlp or switch to cookie-based auth (--cookies from a logged-in browser session).
Defensive patterns
Strategy: try-catch
Try / catch
try:
ydl.extract_info(url)
except ExtractorError as e:
if 'Login failed, TennisTV said' in str(e):
log.error('TennisTV API: %s', str(e)) # contains errorMessage
prompt_reauth()
else:
raise Prevention
- Verify TennisTV credentials in a browser after any password change.
- Keep subscriptions active; API login errors often accompany lapsed entitlements.
- If the error envelope looks garbled, the API changed — upgrade the extractor.
When it happens
Trigger: Submitting credentials that the TennisTV login API rejects: wrong password (errorCode set), unknown email, or account-level refusal; also fires when the API changes its error envelope shape so error.errorCode becomes truthy unexpectedly.
Common situations: Expired/changed passwords; API contract changes after TennisTV site updates; accounts locked for too many attempts; free accounts trying to fetch subscriber content.
Related errors
- We're sorry, but either the User ID or Password entered is n
- Unable to login: %s said: %s
- Unable to login: %s
- Unable to login: %s
- Unable to login: %s
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/750c7e65c68c3deb.
Report an issue: GitHub.