ytdl-org/youtube-dl · error · ExtractorError

Cannot decrypt nsig without player_url

Error message

Cannot decrypt nsig without player_url

What it means

Raised at the top of YoutubeIE._decrypt_nsig when the n-parameter decryption is attempted with player_url=None. The nsig function must be extracted from the player's JavaScript, so without a player URL there is nothing to load the code from. This indicates the caller failed to obtain the player URL from ytplayer config or streaming data.

Solutions

  1. Ensure the full watch page or player response is downloaded so player_url can be extracted before format URL processing.
  2. Update youtube-dl/yt-dlp — extraction of player_url is regularly patched as YouTube changes.
  3. If calling internals yourself, always resolve player_url via _extract_player_url first and pass it to _unthrottle_format_urls/_decrypt_nsig.
  4. As a stopgap, accept throttled URLs (skip nsig) — downloads still work but may be rate-limited by YouTube.

Example fix

// before
self._decrypt_nsig(n, video_id, None)

// after
player_url = self._extract_player_url(...) or self._search_regex(
    r'jsUrl":\s*"([^"]+)', player_response, 'player url')
self._decrypt_nsig(n, video_id, player_url)
Defensive patterns

Strategy: validation

Validate before calling

def can_decrypt_nsig(player_url) -> bool:
    return player_url is not None

Try / catch

try:
    url = self._decrypt_nsig(n, video_id, player_url)
except ExtractorError as e:
    if 'without player_url' in str(e):
        player_url = self._extract_player_url(...) or resolve_player_url(video_id)
        url = self._decrypt_nsig(n, video_id, player_url)
    else:
        raise

Prevention

When it happens

Trigger: Calling _decrypt_nsig (directly or via _unthrottle_format_urls) for a format whose URL has an 'n' query parameter while player_url was never extracted — e.g. missing player response field, age-gated/cookie-only pages where the player config is absent, or API responses built without a player URL.

Common situations: YouTube serves formats needing n-decryption but the extractor path did not capture player_url (page layout change, embedded API responses, consent/age walls); downstream forks calling the internal API without threading player_url through.

Related errors


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

Appendix: source

Thrown at youtube_dl/extractor/youtube.py:1986

        return inner

    def _decrypt_signature(self, s, video_id, player_url):
        """Turn the encrypted s field into a working signature"""
        extract_sig = self._cached(
            self._extract_signature_function, 'sig', player_url, self._signature_cache_id(s))
        func = extract_sig(video_id, player_url, s)
        self._print_sig_code(func, s)
        return func(s)

    # from yt-dlp
    # See also:
    # 1. https://github.com/ytdl-org/youtube-dl/issues/29326#issuecomment-894619419
    # 2. https://code.videolan.org/videolan/vlc/-/blob/4fb284e5af69aa9ac2100ccbdd3b88debec9987f/share/lua/playlist/youtube.lua#L116
    # 3. https://github.com/ytdl-org/youtube-dl/issues/30097#issuecomment-950157377
    def _decrypt_nsig(self, n, video_id, player_url):
        """Turn the encrypted n field into a working signature"""
        if player_url is None:
            raise ExtractorError('Cannot decrypt nsig without player_url')

        try:
            jsi, player_id, func_code = self._extract_n_function_code(video_id, player_url)
        except ExtractorError as e:
            raise ExtractorError('Unable to extract nsig function code', cause=e)
        if self.get_param('youtube_print_sig_code'):
            self.to_screen('Extracted nsig function from {0}:\n{1}\n'.format(
                player_id, func_code[1]))

        try:
            extract_nsig = self._cached(self._extract_n_function_from_code, 'nsig func', player_url)
            ret = extract_nsig(jsi, func_code)(n)
        except JSInterpreter.Exception as e:
            self.report_warning(
                '%s (%s %s)' % (
                    'Unable to decode n-parameter: expect download to be blocked or throttled',
                    error_to_compat_str(e),
                    traceback.format_exc()),

View on GitHub (pinned to 956b8c5855)