Skip to content

yt-dlp YouTube JS Challenge Fix (Fedora)

Problem

When running yt-dlp on Fedora, downloads may fail with the following warnings and errors:

WARNING: [youtube] No supported JavaScript runtime could be found.
WARNING: [youtube] [jsc:deno] Challenge solver lib script version 0.3.2 is not supported (supported version: 0.4.0)
WARNING: [youtube] 0qhgPKRzlvs: n challenge solving failed: Some formats may be missing.
ERROR: Did not get any data blocks
ERROR: fragment 1 not found, unable to continue

This causes subtitle downloads (and sometimes video formats) to fail silently, with the MP4 completing but subtitles being skipped.

Root Causes

  1. No JavaScript runtime installed — yt-dlp requires Deno or Node.js to solve YouTube's JS challenges
  2. Outdated yt-dlp — the bundled challenge solver script is behind the required version
  3. Remote challenge solver not enabled — the updated solver script must be explicitly fetched

Fix

1. Install Deno

Deno is not in the Fedora repos. Install via the official installer:

curl -fsSL https://deno.land/install.sh | sh
sudo mv ~/.deno/bin/deno /usr/local/bin/deno
deno --version

Alternatively, Node.js works and is available via sudo dnf install nodejs.

2. Update yt-dlp

sudo pip install -U yt-dlp --break-system-packages

If installed via standalone binary: yt-dlp -U

3. Enable Remote Challenge Solver

Add --remote-components ejs:github to the yt-dlp command. This fetches the latest JS challenge solver from GitHub at runtime:

yt-dlp -f 'bestvideo[vcodec^=avc]+bestaudio[ext=m4a]/bestvideo+bestaudio' \
  --merge-output-format mp4 \
  -o "/plex/plex/%(title)s.%(ext)s" \
  --write-auto-subs --embed-subs \
  --remote-components ejs:github \
  https://www.youtube.com/watch?v=VIDEO_ID

4. Persist the Config

Create a yt-dlp config file so --remote-components is applied automatically:

mkdir -p ~/.config/yt-dlp
echo '--remote-components ejs:github' > ~/.config/yt-dlp/config

Maintenance

YouTube pushes extractor changes frequently. Keep yt-dlp current.

Updating: the -U trap + avoid duplicate installs

yt-dlp -U does not work when yt-dlp was installed via pip/PyPI — the PyPI build deliberately disables the self-updater:

ERROR: You installed yt-dlp with pip or using the wheel from PyPi; Use that to update

Update through pip instead. Pick one install method and stick to it — running both a user install and a system install leaves two copies that drift out of sync (one updates, the other stays stale and shadows it depending on $PATH / sudo).

Recommended — single user install (no sudo):

pip3 install -U --user yt-dlp

This lives in ~/.local/bin/yt-dlp and is first on a normal user's $PATH. Update it the same way; never use sudo.

Alternative — system-wide (Fedora, PEP 668):

sudo pip install -U yt-dlp --break-system-packages

Only use --break-system-packages if you intentionally want a root-owned copy in /usr/local. Do not mix it with a --user install.

Check for and remove a duplicate install:

which -a yt-dlp            # more than one path = duplicate installs
sudo pip3 uninstall -y yt-dlp   # removes the /usr/local (system) copy + its wrapper

If installed via the standalone binary (not pip), yt-dlp -U is the correct updater.


Known Limitations

n-Challenge Failure: "found 0 n function possibilities"

Even with Deno installed, the remote solver downloaded, and yt-dlp up to date, some YouTube player versions can still fail n-challenge solving:

WARNING: [youtube] [jsc] Error solving n challenge request using "deno" provider:
Error running deno process (returncode: 1): error: Uncaught (in promise)
"found 0 n function possibilities".
WARNING: [youtube] n challenge solving failed: Some formats may be missing.
ERROR: [youtube] Requested format is not available.

This is a known upstream issue tied to specific YouTube player builds (e.g. e42f4bf8). It is not fixable locally — it requires a yt-dlp patch when YouTube rotates the player.

Workaround: Use a permissive format fallback instead of forcing AVC:

yt-dlp -f 'bestvideo+bestaudio/best' \
  --merge-output-format mp4 \
  -o "/plex/plex/%(title)s.%(ext)s" \
  --write-auto-subs --embed-subs \
  --remote-components ejs:github \
  https://www.youtube.com/watch?v=VIDEO_ID

This lets yt-dlp pick the best available format rather than failing on a missing AVC stream. To inspect what formats are actually available:

yt-dlp --list-formats --remote-components ejs:github \
  https://www.youtube.com/watch?v=VIDEO_ID

HTTP 429 Too Many Requests

429 errors (usually on subtitle downloads) are a separate issue from the JS challenge — they're caused by broken browser impersonation (curl_cffi) or YouTube's per-IP subtitle rate bucket, not by the solver. See the dedicated article: yt-dlp HTTP 429: Too Many Requests.

yt-dlp-ejs Version Drift

If yt-dlp -U reports yt-dlp is current but you still see:

WARNING: Challenge solver lib script version 0.3.2 is not supported ... supported version: 0.8.0

…then the EJS solver helper is stale. yt-dlp -U does not update it. Upgrade explicitly:

pip3 install --user -U yt-dlp-ejs

SABR-Only Streaming Warning

Some videos may show:

WARNING: [youtube] Some android_vr client https formats have been skipped as they
are missing a URL. YouTube may have enabled the SABR-only streaming experiment.

This is a YouTube-side experiment. yt-dlp falls back to other clients automatically — no action needed.

pip Version Check

pip show does not accept --break-system-packages. Run separately:

yt-dlp --version
pip show yt-dlp

Format Not Available: Strict AVC+M4A Selector

The format selector bestvideo[vcodec^=avc]+bestaudio[ext=m4a] will hard-fail if YouTube doesn't serve H.264 (AVC) video for a given video:

ERROR: [youtube] Requested format is not available. Use --list-formats for a list of available formats

This is separate from the n-challenge issue — the format simply doesn't exist for that video (common with newer uploads that are VP9/AV1-only).

Fix 1 — Relax the selector to mp4 container without enforcing codec:

yt-dlp -f 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/bestvideo+bestaudio' \
  --merge-output-format mp4 \
  -o "/plex/plex/%(title)s.%(ext)s" \
  --write-auto-subs --embed-subs \
  https://youtu.be/VIDEO_ID

Fix 2 — Let yt-dlp pick best and re-encode to H.264 via ffmpeg (Plex-safe, slower):

yt-dlp -f 'bestvideo+bestaudio' \
  --merge-output-format mp4 \
  --recode-video mp4 \
  -o "/plex/plex/%(title)s.%(ext)s" \
  --write-auto-subs --embed-subs \
  https://youtu.be/VIDEO_ID

Use --recode-video mp4 when Plex direct play is required and the source stream may be VP9/AV1. Requires ffmpeg.

Inspect available formats first:

yt-dlp --list-formats https://youtu.be/VIDEO_ID