ytdl-org/youtube-dl · error · ExtractorError

This video is protected by a passcode, use the…

Error message

This video is protected by a passcode, use the --video-password option

What it means

Raised by the Zoom extractor when the recording page contains a 'password_form' (the recording is protected by a passcode) but no --video-password option was supplied. It tells the user the download cannot proceed without the passcode.

Solutions

  1. Get the passcode from the person who shared the recording link (usually alongside the URL)
  2. Supply it with --video-password '<passcode>'
  3. Alternatively use a URL that already embeds the passcode ( '?pwd=...' ) if the sharer provided one

Example fix

# before
youtube-dl 'https://zoom.us/rec/share/abc-def'
# after
youtube-dl --video-password '123456' 'https://zoom.us/rec/share/abc-def'
Defensive patterns

Strategy: validation

Validate before calling

# before calling youtube_dl, require the passcode for known Zoom share links
if 'zoom.us/rec/' in url or 'zoom.us/rec/share/' in url:
    assert options.get('videopassword'), 'Zoom recording URL needs --video-password'

Try / catch

try:
    ydl.download([url])
except ExtractorError as e:
    if 'protected by a passcode' in str(e):
        prompt_for_password_and_retry(url)  # prompt once, then set ydl params['videopassword']

Prevention

When it happens

Trigger: Running youtube-dl against a shared Zoom cloud-recording URL that has a passcode, without passing --video-password. The extractor detects the hidden password form on the page and immediately raises (expected=True).

Common situations: Following a recording link from email/chat where the passcode is in a separate part of the message; company Zoom accounts that enforce passcodes on all shared recordings.

Related errors


AI-assisted analysis of ytdl-org/youtube-dl@956b8c5855 (2026-08-14). Data as JSON: /api/errors/875d17db358bc2f5. Report an issue: GitHub.

Appendix: source

Thrown at youtube_dl/extractor/zoom.py:40

        'info_dict': {
            'id': 'dUk_CNBETmZ5VA2BwEl-jjakPpJ3M1pcfVYAPRsoIbEByGsLjUZtaa4yCATQuOL3der8BlTwxQePl_j0.EImBkXzTIaPvdZO5',
            'ext': 'mp4',
            'title': 'China\'s "two sessions" and the new five-year plan',
        }
    }

    def _real_extract(self, url):
        base_url, play_id = re.match(self._VALID_URL, url).groups()
        webpage = self._download_webpage(url, play_id)

        try:
            form = self._form_hidden_inputs('password_form', webpage)
        except ExtractorError:
            form = None
        if form:
            password = self._downloader.params.get('videopassword')
            if not password:
                raise ExtractorError(
                    'This video is protected by a passcode, use the --video-password option', expected=True)
            is_meeting = form.get('useWhichPasswd') == 'meeting'
            validation = self._download_json(
                base_url + 'rec/validate%s_passwd' % ('_meet' if is_meeting else ''),
                play_id, 'Validating passcode', 'Wrong passcode', data=urlencode_postdata({
                    'id': form[('meet' if is_meeting else 'file') + 'Id'],
                    'passwd': password,
                    'action': form.get('action'),
                }))
            if not validation.get('status'):
                raise ExtractorError(validation['errorMessage'], expected=True)
            webpage = self._download_webpage(url, play_id)

        data = self._parse_json(self._search_regex(
            r'(?s)window\.__data__\s*=\s*({.+?});',
            webpage, 'data'), play_id, js_to_json)

        return {

View on GitHub (pinned to 956b8c5855)