ytdl-org/youtube-dl · error · ExtractorError
Unable to login: %s
Error message
Unable to login: %s
What it means
Raised by the AnimeOnDemand login flow when the POST response lacks both '>Logout<' and 'href="/users/sign_out"' and an alert-styled <p> error was scraped from the page. The scraped alert text (German site messages like 'E-Mail oder Passwort falsch') is embedded into the message. Marked expected=True.
Source
Thrown at youtube_dl/extractor/animeondemand.py:92
post_url = self._search_regex(
r'<form[^>]+action=(["\'])(?P<url>.+?)\1', login_page,
'post url', default=self._LOGIN_URL, group='url')
if not post_url.startswith('http'):
post_url = urljoin(self._LOGIN_URL, post_url)
response = self._download_webpage(
post_url, None, 'Logging in',
data=urlencode_postdata(login_form), headers={
'Referer': self._LOGIN_URL,
})
if all(p not in response for p in ('>Logout<', 'href="/users/sign_out"')):
error = self._search_regex(
r'<p[^>]+\bclass=(["\'])(?:(?!\1).)*\balert\b(?:(?!\1).)*\1[^>]*>(?P<error>.+?)</p>',
response, 'error', default=None, group='error')
if error:
raise ExtractorError('Unable to login: %s' % error, expected=True)
raise ExtractorError('Unable to log in')
def _real_initialize(self):
self._login()
def _real_extract(self, url):
anime_id = self._match_id(url)
webpage = self._download_webpage(url, anime_id)
if 'data-playlist=' not in webpage:
self._download_webpage(
self._APPLY_HTML5_URL, anime_id,
'Activating HTML5 beta', 'Unable to apply HTML5 beta')
webpage = self._download_webpage(url, anime_id)
csrf_token = self._html_search_meta(
'csrf-token', webpage, 'csrf token', fatal=True)View on GitHub (pinned to 956b8c5855)
Solutions
- Verify credentials by logging in at anime-on-demand.de in a browser
- Confirm the subscription is active — locked accounts often produce alert errors on login POST
- If login works in the browser but not here, the alert markup likely changed; check upstream extractor updates
Defensive patterns
Strategy: try-catch
Try / catch
try:
ydl.extract_info(url)
except ExtractorError as e:
if 'Unable to login' in str(e):
# e.msg carries the German alert text; 'Unable to log in' (no colon) means markup changed
prompt_relogin('animeondemand', detail=str(e)) Prevention
- Verify the AnimeOnDemand subscription is active before automating — locked accounts fail at login POST
- Distinguish the two variants: 'Unable to login: <alert>' = credentials; bare 'Unable to log in' = site markup changed
When it happens
Trigger: POST to the login form URL returns a page without logout markers; regex finds class containing 'alert' with inner text, e.g. wrong credentials or account restrictions; Devise/Rails login errors surfaced as alert paragraphs.
Common situations: Wrong --username/--password; account without an active Anime-on-Demand subscription; site markup change altering the alert class so only the generic 'Unable to log in' appears instead.
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/5c63ec2a22017c2f.
Report an issue: GitHub.