ytdl-org/youtube-dl · error · ExtractorError

Unable to log in

Error message

Unable to log in

What it means

The fallback branch of BBCCoUkIE._login: the login POST ended up back on the sign-in page (self._LOGIN_URL appears in the response URL) but no element with class 'form-message' could be extracted from the returned HTML. Unlike its sibling error 42, there is no scraped reason, so the extractor can only report the bare failure. This usually means the page structure changed or the response was an empty/JS-rendered page rather than a credential rejection.

Source

Thrown at youtube_dl/extractor/bbc.py:296

        login_form.update({
            'username': username,
            'password': password,
        })

        post_url = urljoin(self._LOGIN_URL, self._search_regex(
            r'<form[^>]+action=(["\'])(?P<url>.+?)\1', login_page,
            'post url', default=self._LOGIN_URL, group='url'))

        response, urlh = self._download_webpage_handle(
            post_url, None, 'Logging in', data=urlencode_postdata(login_form),
            headers={'Referer': self._LOGIN_URL})

        if self._LOGIN_URL in urlh.geturl():
            error = clean_html(get_element_by_class('form-message', response))
            if error:
                raise ExtractorError(
                    'Unable to login: %s' % error, expected=True)
            raise ExtractorError('Unable to log in')

    def _real_initialize(self):
        self._login()

    class MediaSelectionError(Exception):
        def __init__(self, id):
            self.id = id

    def _extract_asx_playlist(self, connection, programme_id):
        asx = self._download_xml(connection.get('href'), programme_id, 'Downloading ASX playlist')
        return [ref.get('href') for ref in asx.findall('./Entry/ref')]

    def _extract_items(self, playlist):
        return playlist.findall('./{%s}item' % self._EMP_PLAYLIST_NS)

    def _extract_medias(self, media_selection):
        error = media_selection.get('result')
        if error:

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Verify manually in a browser (with devtools) what the failed-login response looks like; confirm whether the error text still lives in class 'form-message'.
  2. Clear cached cookies and retry login from a clean session.
  3. Confirm the credentials are valid; a silent bounce can still be a credential failure with the message moved client-side.
  4. If the class name changed, update get_element_by_class('form-message', response) in bbc.py:296 to the new selector; report upstream if so.
  5. Skip login entirely — most BBC programmes extract anonymously.

Example fix

// before
if self._LOGIN_URL in urlh.geturl():
    error = clean_html(get_element_by_class('form-message', response))
    if error:
        raise ExtractorError('Unable to login: %s' % error, expected=True)
    raise ExtractorError('Unable to log in')

// after
if self._LOGIN_URL in urlh.geturl():
    error = clean_html(get_element_by_class('form-message', response))
    if error:
        raise ExtractorError('Unable to login: %s' % error, expected=True)
    raise ExtractorError('Unable to log in: sign-in page re-served without an error message; the BBC login flow may have changed', expected=True)
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(url, username=USER, password=PASS)
except ExtractorError as e:
    if str(e) == 'Unable to log in':
        # silent bounce: clear cookies and retry once, then give up
        clear_cookie_file()
        retry_once(url, anonymous=True)
    else:
        raise

Prevention

When it happens

Trigger: Login POST redirects back to the sign-in URL AND the response HTML lacks a form-message element — e.g. BBC renders errors via JavaScript after page load, returns an interstitial/captcha page, or the scraped form action posted to a URL that bounces silently back to sign-in.

Common situations: BBC redesigned the sign-in page and renamed the error CSS class; bot detection serving a challenge page instead of the normal form response; cookies from a previous session confusing the flow; the form action regex matched the wrong form on the page.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/de1d01716198a56f. Report an issue: GitHub.