1. yt-dlp
  2. HTTP Error 403

HTTP Error 403: Forbidden

yt-dlp read the video and its formats, then YouTube refused the file itself. Five causes, the log line that names each, and the fix.

The error#

1ERROR: unable to download video data: HTTP Error 403: Forbidden

In yt-dlp 2026.10.26 this line comes from process_info in YoutubeDL.py. It catches a network exception while the file is being fetched and prints unable to download video data: {err}. The {err} part is an HTTPError, whose text is always HTTP Error {status}: {reason}.

So by the time you see it, extraction worked: the title, the format list and the chosen format were all read. YouTube refused the request for the media itself. A private or deleted video never gets this far; it stops earlier with YouTube's own reason.

What causes it#

  1. An old yt-dlp. YouTube changes its player, and an old release keeps using the one that stopped working. On 2025-10-21 the maintainers traced a wave of these 403s to "the pinned player beginning to stop working", and the fix shipped the next day (issue 14680).
  2. No JavaScript runtime. Since that fix, solving YouTube's challenges takes an external runtime. Without one, and without cookies, yt-dlp 2026.10.26 falls back to a single player client, visionos, and warns that some formats may be missing.
  3. A format that needed a PO token. Formats from some clients are skipped without a token because, in yt-dlp's words, "they may yield HTTP Error 403". If a PO token provider plugin is installed, the provider itself can be the fault: intermittent 403s in August 2026 were closed as a duplicate of a provider bug (issues 17395 and 17368).
  4. A forced format. -f with a fixed format id can pick one stream YouTube will not serve, while the default choice would have worked.
  5. The address you run from. A server in a data centre is trusted less than a home connection, so a command that works on your laptop can fail in production.

How to tell which one it is#

Run the same URL again with -v and read the lines before the error.

You seeCause
[debug] yt-dlp version older than the latest release1
No supported JavaScript runtime could be found2
Signature solving failed or n challenge solving failed2
require a GVS PO Token which was not provided3
The download works when you remove -f4
The same command works from home, fails on the server5

How to fix it#

Work down the list; most people stop at step 2.

1. Update. The standalone build updates itself. With pip, the [default] extra also installs the challenge solver scripts, yt-dlp-ejs.

1yt-dlp -U2python3 -m pip install -U "yt-dlp[default]"3yt-dlp --version

2. Install a JavaScript runtime. Deno is the default and needs version 2.3.0 or later. Node 22 or later works when you name it.

1curl -fsSL https://deno.land/install.sh | sh2yt-dlp --js-runtimes node "https://www.youtube.com/watch?v=VIDEO_ID"

3. Stop forcing the format. Remove -f, or give a chain with a fallback, so yt-dlp can use any stream that is served. Sorting with -S picks a preference without failing when one id is missing.

1yt-dlp -f "bv*+ba/b" "https://www.youtube.com/watch?v=VIDEO_ID"2yt-dlp -S "res:1080,ext" "https://www.youtube.com/watch?v=VIDEO_ID"

4. Sort out the PO token warning. Follow yt-dlp's PO Token Guide, and if you use a provider plugin, update it before anything else.

5. Change the address, or add cookies. A residential connection removes cause 5. Cookies from a signed-in browser (--cookies-from-browser firefox) can get a server through, at a price: a maintainer warns that Google "will block/ban accounts for abusive behavior", so use an account you can lose.

When the file was never the point#

Plenty of yt-dlp scripts only want what is around the video: --dump-json for the details, --write-auto-subs --skip-download for the captions. If that is your job, the 403 is a fight you do not need to have. GET /v1/youtube/video returns the title, description, exact views and likes, chapters and the list of caption tracks, and GET /v1/youtube/video/transcript returns the captions as text. Neither needs a format, a runtime or cookies on your side.

SocialScrape does not download YouTube video or audio files. If the file is what you need, the fixes above are the way. Each video costs 1 credit, a failed request costs nothing, and a new account starts with 100 free credits.

Questions

Does a 403 mean the video is private?

No. A private, removed or members-only video stops at extraction with YouTube's reason, before any download starts.

Why does it work on my laptop but not on my server?

YouTube judges the address. One maintainer put it plainly: "Youtube blocked anonymous access from many datacenter IPs."

Will a VPN fix it?

Only if its exit is trusted more than yours. Many VPN exits sit in data centres too, and a maintainer's advice for the related bot check was to turn the VPN off.

Is the format id the same on every video?

No. Each video lists its own formats, and one picture can have two ids, one per protocol. Read the list with yt-dlp -F before you pick one.

100 free credits. No card needed.

Start pulling social data.