ytdl-org/youtube-dl · error · ExtractorError

Unable to login: %s

Error message

Unable to login: %s

What it means

Thrown during Lynda authentication when a step of the multi-stage login flow returns a JSON body containing an error under one of the watched keys (passed as key_or_keys to _check_error). It is expected=True, so it signals a credential or account problem (bad password, expired account, captcha) rather than an internal failure. The '%s' is the raw error string from lynda.com.

Source

Thrown at youtube_dl/extractor/lynda.py:33


class LyndaBaseIE(InfoExtractor):
    _SIGNIN_URL = 'https://www.lynda.com/signin/lynda'
    _PASSWORD_URL = 'https://www.lynda.com/signin/password'
    _USER_URL = 'https://www.lynda.com/signin/user'
    _ACCOUNT_CREDENTIALS_HINT = 'Use --username and --password options to provide lynda.com account credentials.'
    _NETRC_MACHINE = 'lynda'

    def _real_initialize(self):
        self._login()

    @staticmethod
    def _check_error(json_string, key_or_keys):
        keys = [key_or_keys] if isinstance(key_or_keys, compat_str) else key_or_keys
        for key in keys:
            error = json_string.get(key)
            if error:
                raise ExtractorError('Unable to login: %s' % error, expected=True)

    def _login_step(self, form_html, fallback_action_url, extra_form_data, note, referrer_url):
        action_url = self._search_regex(
            r'<form[^>]+action=(["\'])(?P<url>.+?)\1', form_html,
            'post url', default=fallback_action_url, group='url')

        if not action_url.startswith('http'):
            action_url = compat_urlparse.urljoin(self._SIGNIN_URL, action_url)

        form_data = self._hidden_inputs(form_html)
        form_data.update(extra_form_data)

        response = self._download_json(
            action_url, None, note,
            data=urlencode_postdata(form_data),
            headers={
                'Referer': referrer_url,
                'X-Requested-With': 'XMLHttpRequest',

View on GitHub (pinned to 956b8c5855)

Solutions

  1. Verify the lynda.com credentials are correct by logging in with a browser.
  2. Provide credentials explicitly: --username and --password, or a netrc entry for machine 'lynda'.
  3. Pass --cookies with an exported browser cookie jar to bypass the form login entirely.
  4. If credentials are valid but the error persists, the login flow likely changed; update youtube-dl (the Lynda extractor is frequently patched) or report an issue.
Defensive patterns

Strategy: validation

Validate before calling

# Validate credentials shape before invoking the extractor
import getpass, netrc
try:
    n = netrc.netrc()
    auth = n.authenticators('lynda')
    ok = bool(auth and auth[0] and auth[2])
except FileNotFoundError:
    ok = '--username' in sys.argv or False
assert ok, 'Provide lynda credentials via --username/--password or a netrc entry'

Type guard

def has_lynda_credentials(opts):
    return bool(getattr(opts, 'username', None) and getattr(opts, 'password', None)) or getattr(opts, 'cookiefile', None) is not None

Try / catch

try:
    ydl.download([url])
except ExtractorError as e:
    if 'Unable to login' in str(e):
        # credentials/account problem: fix inputs, do not retry unchanged
        print('Check lynda credentials or supply --cookies')
    else:
        raise

Prevention

When it happens

Trigger: Any _login_step POST whose response JSON contains a truthy value under the checked key(s) (e.g. 'error', 'ErrorMessage') triggers this immediately after the form is submitted with the user's credentials.

Common situations: Wrong username/password supplied via --username/--password or .netrc (machine 'lynda'); expired or cancelled Lynda subscription; Lynda login flow changed (new CSRF field, new endpoint) so the parsed response now contains an error blob; forced captcha/2FA on the account.

Related errors


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