ytdl-org/youtube-dl · error · ExtractorError

Unable to login: %s

Error message

Unable to login: %s

What it means

Raised by PluralsightIE._login when the login POST response contains a '<span class="field-validation-error">' element. The span's text (ASP.NET-style validation message, e.g. 'The Email field is required' or 'Invalid login attempt') is interpolated: 'Unable to login: <error>'. Expected=True.

Source

Thrown at youtube_dl/extractor/pluralsight.py:198

        })

        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 = 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'})

        error = self._search_regex(
            r'<span[^>]+class="field-validation-error"[^>]*>([^<]+)</span>',
            response, 'error message', default=None)
        if error:
            raise ExtractorError('Unable to login: %s' % error, expected=True)

        if all(not re.search(p, response) for p in (
                r'__INITIAL_STATE__', r'["\']currentUser["\']',
                # new layout?
                r'>\s*Sign out\s*<')):
            BLOCKED = 'Your account has been blocked due to suspicious activity'
            if BLOCKED in response:
                raise ExtractorError(
                    'Unable to login: %s' % BLOCKED, expected=True)
            MUST_AGREE = 'To continue using Pluralsight, you must agree to'
            if any(p in response for p in (MUST_AGREE, '>Disagree<', '>Agree<')):
                raise ExtractorError(
                    'Unable to login: %s some documents. Go to pluralsight.com, '
                    'log in and agree with what Pluralsight requires.'
                    % MUST_AGREE, expected=True)

            raise ExtractorError('Unable to log in')

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Verify credentials at app.pluralsight.com/id/ in a browser; reset password if needed
  2. Use --cookies with an exported logged-in session instead of password login
  3. Wait and retry if repeated attempts locked the account

Example fix

# before
youtube_dl --username me@example.com --password 'typo' PS_URL
# after
youtube_dl --cookies cookies.txt PS_URL  # session exported from logged-in browser
Defensive patterns

Strategy: validation

Validate before calling

# Prove credentials work in a browser first; then smoke-test:
yt-dlp --username "$PS_USER" --password "$PS_PASS" --simulate ONE_URL \
  || echo 'Login rejected — fix credentials before batch'

Try / catch

try:
    ydl.extract_info(url)
except ExtractorError as e:
    if e.expected and str(e).startswith('Unable to login:'):
        sys.exit('Pluralsight: ' + str(e))  # message is the validation text

Prevention

When it happens

Trigger: Submitting the login form and Pluralsight's server-side validation fails: wrong email/password, empty fields, or anti-forgery token mismatch (stale form scrape). Detected by regex over the response HTML.

Common situations: Typo'd credentials in .netrc; password changed since stored; login form requiring reCAPTCHA so plain POST is rejected; account locked after repeated failures.

Related errors


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