{"record":{"id":"0be0f605094f3871","repo":"yt-dlp/yt-dlp","slug":"unable-to-login-twitch-said-message","errorCode":null,"errorMessage":"Unable to login. Twitch said: {message}","messagePattern":"Unable to login\\. Twitch said: (.+?)","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"yt_dlp/extractor/twitch.py","lineNumber":64,"sourceCode":"        'ClipsCards__User': '1cd671bfa12cec480499c087319f26d21925e9695d1f80225aae6a4354f23088',\n        'ShareClipRenderStatus': '0a02bb974443b576f5579aab0fef1d4b7f44e58a8a256f0c5adfead0db70640f',\n        'ChannelCollectionsContent': '5247910a19b1cd2b760939bf4cba4dcbd3d13bdf8c266decd16956f6ef814077',\n        'StreamMetadata': 'ad022ca32220d5523d03a23cbcb5beaa1e0999889c1f8f78f9f2520dafb5cae6',\n        'ComscoreStreamingQuery': 'e1edae8122517d013405f237ffcc124515dc6ded82480a88daef69c83b53ac01',\n        'VideoPreviewOverlay': '9515480dee68a77e667cb19de634739d33f243572b007e98e67184b1a5d8369f',\n        'VideoMetadata': '45111672eea2e507f8ba44d101a61862f9c56b11dee09a15634cb75cb9b9084d',\n        'VideoPlayer_ChapterSelectButtonVideo': '71835d5ef425e154bf282453a926d99b328cdc5e32f36d3a209d0f4778b41203',\n        'VideoPlayer_VODSeekbarPreviewVideo': '07e99e4d56c5a7c67117a154777b0baf85a5ffefa393b213f4bc712ccaf85dd6',\n    }\n\n    @property\n    def _CLIENT_ID(self):\n        return self._configuration_arg(\n            'client_id', ['ue6666qo983tsx6so1t0vnawi233wa'], ie_key='Twitch', casesense=True)[0]\n\n    def _perform_login(self, username, password):\n        def fail(message):\n            raise ExtractorError(\n                f'Unable to login. Twitch said: {message}', expected=True)\n\n        def login_step(page, urlh, note, data):\n            form = self._hidden_inputs(page)\n            form.update(data)\n\n            page_url = urlh.url\n            post_url = self._search_regex(\n                r'<form[^>]+action=([\"\\'])(?P<url>.+?)\\1', page,\n                'post url', default=self._LOGIN_POST_URL, group='url')\n            post_url = urljoin(page_url, post_url)\n\n            headers = {\n                'Referer': page_url,\n                'Origin': 'https://www.twitch.tv',\n                'Content-Type': 'text/plain;charset=UTF-8',\n            }\n","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/yt-dlp/yt-dlp/blob/81ecd58b1394793e6da9998cc19fdb45657f1685/yt_dlp/extractor/twitch.py#L46-L82","documentation":"Raised by TwitchBaseIE._perform_login via its fail() helper when Twitch's web login form rejects the submitted credentials. The {message} placeholder is the failure text parsed from Twitch's login HTML (wrong password, CAPTCHA required, unusual-activity block). It is an expected ExtractorError, i.e. a user/input problem, not an extractor bug.","triggerScenarios":"Downloading any Twitch URL with --username/--password: after POSTing the login form, the returned page indicates failure and fail(message) fires at yt_dlp/extractor/twitch.py:62-64. Typical embedded messages: 'incorrect username or password', CAPTCHA / 'prove you are human', or 'login attempt blocked due to unusual activity'.","commonSituations":"Twitch password login is brittle: accounts with 2FA/OAuth-only, logins from VPN/datacenter IPs triggering CAPTCHA, changed login-form markup in old yt-dlp versions, or simply wrong credentials. Cookie-based auth bypasses the whole password flow.","solutions":["Pass browser cookies instead of password login: yt-dlp --cookies-from-browser chrome <twitch-url> (or export cookies.txt and use --cookies); required for 2FA accounts and far more reliable","Verify the username/password with a normal browser login; watch for typos, trailing spaces, or an expired password","Update yt-dlp (yt-dlp -U or pip install -U yt-dlp); login-page parsing breaks when Twitch changes markup","If on a VPN/datacenter IP, retry from a residential IP to avoid the CAPTCHA/unusual-activity rejection path"],"exampleFix":"# before\nyt-dlp --username USER --password PASS https://www.twitch.tv/videos/123456789\n\n# after\nyt-dlp --cookies-from-browser chrome https://www.twitch.tv/videos/123456789","handlingStrategy":"fallback","validationCode":"import yt_dlp.utils\n\n# Prefer cookie auth up front; password login is the fragile path\ndef has_cookie_auth(opts):\n    return bool(opts.get('cookiefile') or opts.get('cookiesfrombrowser'))\n\nassert has_cookie_auth(ydl_opts) or (username and password), 'no Twitch auth configured'","typeGuard":"from yt_dlp.utils import ExtractorError\n\ndef is_twitch_login_rejection(e: BaseException) -> bool:\n    return isinstance(e, ExtractorError) and str(e).startswith('Unable to login. Twitch said:')","tryCatchPattern":"from yt_dlp import YoutubeDL\nfrom yt_dlp.utils import ExtractorError\n\ntry:\n    with YoutubeDL({'username': u, 'password': p}) as ydl:\n        ydl.download([url])\nexcept ExtractorError as e:\n    if str(e).startswith('Unable to login. Twitch said:'):\n        # Twitch rejected the password flow: fall back to cookie auth\n        with YoutubeDL({'cookiesfrombrowser': ('chrome',)}) as ydl:\n            ydl.download([url])\n    else:\n        raise","preventionTips":["Prefer --cookies/--cookies-from-browser for Twitch; password login breaks often","Store credentials in ~/.netrc instead of shell history or scripts","Keep yt-dlp updated when using interactive login flows"],"tags":["twitch","login","authentication","credentials","captcha"],"backgroundTag":"login-credentials-rejected","analyzedSha":"81ecd58b1394793e6da9998cc19fdb45657f1685","analyzedAt":"2026-08-22T12:21:25.439Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}