{"record":{"id":"c5e3acf9e8b3fcba","repo":"ytdl-org/youtube-dl","slug":"unable-to-login-s-c5e3ac","errorCode":null,"errorMessage":"Unable to login: %s","messagePattern":"Unable to login: (.+?)","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/platzi.py","lineNumber":63,"sourceCode":"            data=urlencode_postdata(login_form),\n            headers={'Referer': self._LOGIN_URL})\n\n        # login succeeded\n        if 'platzi.com/login' not in urlh.geturl():\n            return\n\n        login_error = self._webpage_read_content(\n            urlh, self._LOGIN_URL, None, 'Downloading login error page')\n\n        login = self._parse_json(\n            self._search_regex(\n                r'login\\s*=\\s*({.+?})(?:\\s*;|\\s*</script)', login_error, 'login'),\n            None)\n\n        for kind in ('error', 'password', 'nonFields'):\n            error = str_or_none(login.get('%sError' % kind))\n            if error:\n                raise ExtractorError(\n                    'Unable to login: %s' % error, expected=True)\n        raise ExtractorError('Unable to log in')\n\n\nclass PlatziIE(PlatziBaseIE):\n    _VALID_URL = r'''(?x)\n                    https?://\n                        (?:\n                            platzi\\.com/clases|           # es version\n                            courses\\.platzi\\.com/classes  # en version\n                        )/[^/]+/(?P<id>\\d+)-[^/?\\#&]+\n                    '''\n\n    _TESTS = [{\n        'url': 'https://platzi.com/clases/1311-next-js/12074-creando-nuestra-primera-pagina/',\n        'md5': '8f56448241005b561c10f11a595b37e3',\n        'info_dict': {\n            'id': '12074',","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/platzi.py#L45-L81","documentation":"Raised by Platzi's login flow (_perform_login on the newer API path) when the post-login page's embedded 'login = {...}' JSON contains an error field. The extractor scrapes login_error content via _webpage_read_content, parses the JSON, and for kinds 'error', 'password', 'nonFields' re-raises the site's message as 'Unable to login: <error>' (expected).","triggerScenarios":"Logging in with credentials that Platzi rejects: wrong password (passwordError), invalid email/credentials (error), or form-level errors (nonFields). Occurs only when username/password authentication is attempted.","commonSituations":"Stale .netrc credentials; accounts registered via Google/OAuth only (no native password set); Platzi changing their login page so the login JSON regex fails (then you get a different 'login' search error).","solutions":["Reset/verify the Platzi password at platzi.com, then update --username/--password or .netrc","If the account uses social login only, create a native password in account settings first","Some Platzi content is free — try without credentials to see if login is needed at all"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Smoke-test the credential before a batch run\nyoutube_dl --username \"$PS_USER\" --password \"$PS_PASS\" --simulate 'https://platzi.com/clases/test/1234-test/' || echo 'fix credentials first'","typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if e.expected and str(e).startswith('Unable to login:'):\n        sys.exit('Platzi credentials rejected: ' + str(e))","preventionTips":["Validate credentials with one --simulate call before batches","Store credentials in .netrc (chmod 600), not shell history","Set a native password for social-login-only accounts"],"tags":["platzi","authentication","login","extractor-error","expected"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}