yt-dlp/yt-dlp · error · ExtractorError

Invalid password

Error message

Invalid password

What it means

PlaySuisseIE._perform_login (yt_dlp/extractor/playsuisse.py:207) performs the second auth step, POSTing the password to {LOGIN_BASE}/verification-srv/v2/authenticate/authenticate/password. Any ExtractorError from that call is re-labelled 'Invalid password' (expected=True); like the username step, the catch-all also hides network or schema errors behind this message.

Source

Thrown at yt_dlp/extractor/playsuisse.py:207

                    'request_id': request_id,
                    'medium_id': 'PASSWORD',
                    'type': 'password',
                    'identifier': username,
                }).encode())['data']['exchange_id']['exchange_id']
        except ExtractorError:
            raise ExtractorError('Invalid username', expected=True)

        try:
            login_data = self._download_json(
                f'{self._LOGIN_BASE}/verification-srv/v2/authenticate/authenticate/password', None,
                'Submitting password', headers={'content-type': 'application/json'}, data=json.dumps({
                    'requestId': request_id,
                    'exchange_id': exchange_id,
                    'type': 'password',
                    'password': password,
                }).encode())['data']
        except ExtractorError:
            raise ExtractorError('Invalid password', expected=True)

        authorization_code = parse_qs(self._request_webpage(
            f'{self._LOGIN_BASE}/login-srv/verification/login', None, 'Logging in',
            data=urlencode_postdata({
                'requestId': request_id,
                'exchange_id': login_data['exchange_id']['exchange_id'],
                'verificationType': 'password',
                'sub': login_data['sub'],
                'status_id': login_data['status_id'],
                'rememberMe': True,
                'lat': '',
                'lon': '',
            })).url)['code'][0]

        self._ID_TOKEN = self._download_json(
            f'{self._LOGIN_BASE}/proxy/token', None, 'Downloading token', data=b'', query={
                'client_id': self._CLIENT_ID,
                'redirect_uri': 'https://www.playsuisse.ch/auth',

View on GitHub (pinned to 81ecd58b13)

Solutions

  1. Confirm the exact password in a browser login at playsuisse.ch.
  2. Quote the password properly on the CLI or store it in netrc to avoid shell mangling.
  3. Retry once to rule out the transient-failure case that shares this message.
  4. Update yt-dlp if both steps behave inconsistently, since JSON paths may have moved.
Defensive patterns

Strategy: try-catch

Type guard

from yt_dlp.utils import ExtractorError

def is_playsuisse_invalid_password(e: BaseException) -> bool:
    """True for the 'Invalid password' wrap from the authenticate/password step."""
    return isinstance(e, ExtractorError) and e.expected and str(e) == 'Invalid password'

Try / catch

from yt_dlp.utils import ExtractorError

try:
    ydl.download([url])
except ExtractorError as e:
    if e.expected and str(e) == 'Invalid password':
        raise CredentialsError('playsuisse rejected the password') from e
    raise

Prevention

When it happens

Trigger: The username step succeeded (a valid exchange_id was obtained) but the password submission failed: wrong password for a known account, or a transient/structural failure in the authenticate/password request.

Common situations: Stale password in netrc after a reset; password containing characters mangled by shell quoting on the command line; occasional network hiccup reported misleadingly as 'Invalid password'.

Related errors


AI-assisted analysis of yt-dlp/yt-dlp@81ecd58b13 (2026-08-22). Data as JSON: /api/errors/837c4723390e0489. Report an issue: GitHub.