{"record":{"id":"13fb4d1e70d47a53","repo":"ytdl-org/youtube-dl","slug":"unable-to-login-s-asks-you-to-accept-new-privacy","errorCode":null,"errorMessage":"Unable to login: %s asks you to accept new Privacy Policy. Go to https://%s/ and accept.","messagePattern":"Unable to login: (.+?) asks you to accept new Privacy Policy\\. Go to https://(.+?)/ and accept\\.","errorType":"exception","errorClass":"ExtractorError","httpStatus":null,"severity":"error","filePath":"youtube_dl/extractor/teachable.py","lineNumber":87,"sourceCode":"        })\n\n        post_url = self._search_regex(\n            r'<form[^>]+action=([\"\\'])(?P<url>(?:(?!\\1).)+)\\1', login_page,\n            'post url', default=login_url, group='url')\n\n        if not post_url.startswith('http'):\n            post_url = urljoin(login_url, post_url)\n\n        response = self._download_webpage(\n            post_url, None, 'Logging in to %s' % site,\n            data=urlencode_postdata(login_form),\n            headers={\n                'Content-Type': 'application/x-www-form-urlencoded',\n                'Referer': login_url,\n            })\n\n        if '>I accept the new Privacy Policy<' in response:\n            raise ExtractorError(\n                'Unable to login: %s asks you to accept new Privacy Policy. '\n                'Go to https://%s/ and accept.' % (site, site), expected=True)\n\n        # Successful login\n        if is_logged(response):\n            self._logged_in = True\n            return\n\n        message = get_element_by_class('alert', response)\n        if message is not None:\n            raise ExtractorError(\n                'Unable to login: %s' % clean_html(message), expected=True)\n\n        raise ExtractorError('Unable to log in')\n\n\nclass TeachableIE(TeachableBaseIE):\n    _VALID_URL = r'''(?x)","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/ytdl-org/youtube-dl/blob/956b8c585591b401a543e409accb163eeaaa1193/youtube_dl/extractor/teachable.py#L69-L105","documentation":"Raised by TeachableBaseIE._login when the POST response to the site's login form contains '>I accept the new Privacy Policy<'. The site refuses to complete login until the account has accepted the new policy, so no credential retry can succeed. Marked expected=True and includes the site hostname so the user knows where to go.","triggerScenarios":"Passing --username/--password (or netrc) for a Teachable school site whose account has a pending Privacy Policy acceptance; the login POST succeeds HTTP-wise but returns the policy-acceptance page.","commonSituations":"GDPR-era policy rollouts across all Teachable-hosted schools (sites like course sites on teachable.com or custom domains); accounts dormant since before the policy change.","solutions":["Open https://<site>/ in a browser, log in once, click 'I accept the new Privacy Policy', then retry the CLI download.","Keep credentials in .netrc for the Teachable school so re-login after acceptance is automatic.","If managing many accounts, do the acceptance step as part of account provisioning."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Detect pending policy acceptance by fetching login page state first\n# (practical equivalent: just do the one-time acceptance in a browser)","typeGuard":null,"tryCatchPattern":"try:\n    ydl.extract_info(url)\nexcept ExtractorError as e:\n    if e.expected and 'Privacy Policy' in str(e):\n        prompt_user_to_accept(site)  # message contains the exact https://<site>/ URL\n    else:\n        raise","preventionTips":["Accept policy changes promptly when sites announce them; CLI logins break until you do.","Store Teachable credentials per-school in .netrc.","Treat 'asks you to accept' messages as account-state issues, not credential errors."],"tags":["login","policy","expected-error","teachable"],"backgroundTag":null,"analyzedSha":"956b8c585591b401a543e409accb163eeaaa1193","analyzedAt":"2026-08-14T18:59:47.863Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}