ytdl-org/youtube-dl · error · ExtractorError
%s said: %s
Error message
%s said: %s
What it means
Raised by the Linux Academy extractor when the login endpoint returns HTTP 401: the JSON error body's 'description' (or 'code') becomes the message alongside the extractor name. It is expected=True and means the login request itself was rejected — bad credentials or an expired auth flow.
Source
Thrown at youtube_dl/extractor/linuxacademy.py:126
'sso': 'true',
})
login_state_url = urlh.geturl()
try:
login_page = self._download_webpage(
'https://login.linuxacademy.com/usernamepassword/login', None,
'Downloading login page', data=json.dumps(login_data).encode(),
headers={
'Content-Type': 'application/json',
'Origin': 'https://login.linuxacademy.com',
'Referer': login_state_url,
})
except ExtractorError as e:
if isinstance(e.cause, compat_HTTPError) and e.cause.code == 401:
error = self._parse_json(e.cause.read(), None)
message = error.get('description') or error['code']
raise ExtractorError(
'%s said: %s' % (self.IE_NAME, message), expected=True)
raise
callback_page, urlh = self._download_webpage_handle(
'https://login.linuxacademy.com/login/callback', None,
'Downloading callback page',
data=urlencode_postdata(self._hidden_inputs(login_page)),
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'https://login.linuxacademy.com',
'Referer': login_state_url,
})
access_token = self._search_regex(
r'access_token=([^=&]+)', urlh.geturl(),
'access token', default=None)
if not access_token:
access_token = self._parse_json(View on GitHub (pinned to 956b8c5855)
Solutions
- Verify credentials in a browser first
- Update youtube-dl / switch to yt-dlp — the login handshake is version-sensitive
- If MFA blocks headless login, use --cookies with an exported authenticated session
- Read the embedded 'description' text; it usually names the exact refusal reason
Defensive patterns
Strategy: fallback
Try / catch
try:
ydl.download([url])
except ExtractorError as e:
if ' said: ' in str(e):
# login rejected (401): fall back to exported session cookies
switch_to_cookie_auth_and_retry(url)
else:
raise Prevention
- Verify credentials in a browser before scripted login
- Update extractors before debugging — auth-flow breakage is usually fixed upstream
- Use cookie-based auth when MFA is enabled on the account
When it happens
Trigger: Using --username/--password with linuxacademy.com URLs where POST https://login.linuxacademy.com/usernamepassword/login responds 401 with a JSON error — wrong credentials, stale login state url, or the auth flow (state/nonce handshake) having changed.
Common situations: Incorrect email/password; Linux Academy (now Cloud Assessment/TAC Security) changing their auth stack so the two-step login dance breaks; MFA required on the account; old youtube-dl versions predating an auth-flow update.
Related errors
- Unable to log in
- ', '.join(auth['messages'])
- Unable to login: %s
- resp.get('userMessage') or resp['id']
- %s said: %s
AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14).
Data as JSON: /api/errors/ec7ee44b99ab8da9.
Report an issue: GitHub.