ytdl-org/youtube-dl · error · ExtractorError

Unable to login: %s

Error message

Unable to login: %s

What it means

Raised by FrontendMastersBaseIE._login when the POST of the WordPress login form succeeds HTTP-wise but the response contains neither the logout marker nor a parseable MessageAlert error. The '%s' variant appears when an error banner WAS found; a separate bare 'Unable to log in' covers the unparseable case. Expected=True variant means bad credentials or an account issue surfaced by the site.

Source

Thrown at youtube_dl/extractor/frontendmasters.py:69

            'post_url', default=self._LOGIN_URL, group='url')

        if not post_url.startswith('http'):
            post_url = compat_urlparse.urljoin(self._LOGIN_URL, post_url)

        response = self._download_webpage(
            post_url, None, 'Logging in', data=urlencode_postdata(login_form),
            headers={'Content-Type': 'application/x-www-form-urlencoded'})

        # Successful login
        if any(p in response for p in (
                'wp-login.php?action=logout', '>Logout')):
            return

        error = self._html_search_regex(
            r'class=(["\'])(?:(?!\1).)*\bMessageAlert\b(?:(?!\1).)*\1[^>]*>(?P<error>[^<]+)<',
            response, 'error message', default=None, group='error')
        if error:
            raise ExtractorError('Unable to login: %s' % error, expected=True)
        raise ExtractorError('Unable to log in')


class FrontendMastersPageBaseIE(FrontendMastersBaseIE):
    def _download_course(self, course_name, url):
        return self._download_json(
            '%s/courses/%s' % (self._API_BASE, course_name), course_name,
            'Downloading course JSON', headers={'Referer': url})

    @staticmethod
    def _extract_chapters(course):
        chapters = []
        lesson_elements = course.get('lessonElements')
        if isinstance(lesson_elements, list):
            chapters = [url_or_none(e) for e in lesson_elements if url_or_none(e)]
        return chapters

    @staticmethod

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Verify the exact username/password by logging in at frontendmasters.com in a browser
  2. Ensure the account has an active subscription (free accounts cannot download course videos)
  3. Quote credentials properly on the command line to avoid shell mangling of special characters
  4. If the site now requires captcha/2FA, log in via browser and use --cookies instead of --username/--password

Example fix

# before
youtube_dl --username me@example.com --password 'wronpw' 'https://frontendmasters.com/courses/x/'
# ERROR: Unable to login: Invalid username or password

# after
yt-dlp --username me@example.com --password 'correctpw' 'https://frontendmasters.com/courses/x/'
# or
yt-dlp --cookies fm_cookies.txt 'https://frontendmasters.com/courses/x/'
Defensive patterns

Strategy: try-catch

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if 'Unable to login' in str(e):
        alert_credentials_invalid(e)  # check --username/--password; do not loop retries

Prevention

When it happens

Trigger: The login response lacks 'wp-login.php?action=logout' and '>Logout', and the regex class="...MessageAlert...">(?P<error>...)< matches — the site displayed an error such as 'Invalid username' or 'incorrect password'. Occurs with wrong --username/--password or an account without an active FrontendMasters subscription.

Common situations: Typo'd credentials in CI configs; expired subscription accounts; password changes not reflected in stored CLI options; 2FA/captcha interstitials that look like login failures to the regex.

Related errors


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