yt-dlp/yt-dlp · error · ExtractorError

Unable to login: incorrect username and/or password

Error message

Unable to login: incorrect username and/or password

What it means

Raised during Zattoo login when POST {host}/zapi/v2/account/login returns HTTP 400. Zattoo uses 400 for rejected credentials, so the extractor converts it to a clear 'incorrect username and/or password' ExtractorError (expected=True). Any other HTTP status propagates unchanged.

Source

Thrown at yt_dlp/extractor/zattoo.py:40

    def _real_initialize(self):
        if not self._power_guide_hash:
            self.raise_login_required('An account is needed to access this media', method='password')

    def _perform_login(self, username, password):
        try:
            data = self._download_json(
                f'{self._host_url()}/zapi/v2/account/login', None, 'Logging in',
                data=urlencode_postdata({
                    'login': username,
                    'password': password,
                    'remember': 'true',
                }), headers={
                    'Referer': f'{self._host_url()}/login',
                    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                })
        except ExtractorError as e:
            if isinstance(e.cause, HTTPError) and e.cause.status == 400:
                raise ExtractorError(
                    'Unable to login: incorrect username and/or password',
                    expected=True)
            raise

        self._power_guide_hash = data['session']['power_guide_hash']

    def _initialize_pre_login(self):
        session_token = self._download_json(
            f'{self._host_url()}/token.json', None, 'Downloading session token')['session_token']

        # Will setup appropriate cookies
        self._request_webpage(
            f'{self._host_url()}/zapi/v3/session/hello', None,
            'Opening session', data=urlencode_postdata({
                'uuid': str(uuid.uuid4()),
                'lang': 'en',
                'app_version': '1.8.2',
                'format': 'json',

View on GitHub (pinned to 81ecd58b13)

Solutions

  1. Verify the username/password pair by logging in at the same host in a browser
  2. Match the host: extract from the exact domain your account uses (zattoo.com, zattoo.de, etc.) or set --extractor-args accordingly
  3. Quote the password correctly on the CLI (prefer --password via prompt or netrc to avoid shell mangling)
  4. Prefer cookie-based auth (--cookies-from-browser) as an alternative when the API rejects programmatic logins

Example fix

# before
yt-dlp --username me@mail.com --password 'p@ss' "https://zattoo.com/..."

# after (correct quoting + right host, or skip password login entirely)
yt-dlp --username me@mail.com --password 'p@ss word!' "https://zattoo.com/..."
yt-dlp --cookies-from-browser firefox "https://zattoo.com/..."
Defensive patterns

Strategy: validation

Validate before calling

# Sanity-check credentials (and host) before invoking the extractor
username, password = get_credentials()
assert username and username.strip(), 'empty username'
assert password, 'empty password'
host_ok = url.startswith('https://zattoo.')  # match the domain your account belongs to
assert host_ok, 'zattoo host does not match the account region'

Try / catch

from yt_dlp.utils import ExtractorError
try:
    ydl.download([url])
except ExtractorError as e:
    if 'incorrect username and/or password' in str(e):
        invalidate_stored_credentials()  # stop retrying a bad pair
        raise
    raise

Prevention

When it happens

Trigger: Calling a zattoo extractor with --username/--password (or netrc) credentials the API rejects; typos; wrong regional host (zattoo.com vs zattoo.de and other white-label hosts) where the account does not exist.

Common situations: Password changed but config still has the old one; account registered on a different Zattoo regional service than the URL being extracted; special characters in the password mangled by shell quoting; credentials stored in netrc with wrong formatting.

Related errors


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