ytdl-org/youtube-dl · error · ExtractorError

Unable to login: %s

Error message

Unable to login: %s

What it means

Raised by UdemyIE._login when the POST to the login URL succeeded but the response does not look logged-in and the page contains a <div class="form-errors…"> element. The scraped error text (e.g. invalid email/password) is appended to 'Unable to login: '. A sibling unexpected error 'Unable to log in' fires when no form-errors div is present.

Source

Thrown at youtube_dl/extractor/udemy.py:211

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

        response = self._download_webpage(
            self._LOGIN_URL, None, 'Logging in',
            data=urlencode_postdata(login_form),
            headers={
                'Referer': self._ORIGIN_URL,
                'Origin': self._ORIGIN_URL,
            })

        if not is_logged(response):
            error = self._html_search_regex(
                r'(?s)<div[^>]+class="form-errors[^"]*">(.+?)</div>',
                response, 'error message', default=None)
            if error:
                raise ExtractorError('Unable to login: %s' % error, expected=True)
            raise ExtractorError('Unable to log in')

    def _real_extract(self, url):
        lecture_id = self._match_id(url)

        webpage = self._download_webpage(url, lecture_id)

        course_id, _ = self._extract_course_info(webpage, lecture_id)

        try:
            lecture = self._download_lecture(course_id, lecture_id)
        except ExtractorError as e:
            # Error could possibly mean we are not enrolled in the course
            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
                self._enroll_course(url, webpage, course_id)
                lecture = self._download_lecture(course_id, lecture_id)
            else:
                raise

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Verify the email/password pair logs in on udemy.com in a browser.
  2. Quote credentials correctly on the command line (special characters, trailing spaces).
  3. Prefer cookie auth: export cookies from a logged-in browser and use --cookies.
  4. Update to yt-dlp if the login form/markup changed.
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'Unable to login' in str(e):
        verify_credentials_in_browser(username)  # then switch to --cookies
    else:
        raise

Prevention

When it happens

Trigger: Running with --username/--password where authentication fails: wrong credentials, account locked, or Udemy rendering the failure inside the scraped form-errors div.

Common situations: Typo'd passwords, changed/expired passwords, spaces in shell-passed credentials, Udemy A/B markup that hides the div (leading to the generic variant).

Related errors


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