You can use DepotDownloader for years treating manifests as magic numbers from SteamDB. I did. But the moment something fails — a 401, a half-validated install, a build that "downloaded" into mismatched files — the mental model starts paying rent. So here's the machinery, as it actually exists in the protocol and the source code, minus the folklore that's accumulated on forums for a decade.
01What a manifest actually is
A manifest is a serialized file list — a protobuf document that describes one depot at one instant. For every file in the depot it records the path, size, flags, and the list of chunks that make the file up, each identified by the hash of its contents. The manifest ID you paste from SteamDB is a 64-bit number that names one of these documents, and the document is immutable: an update never edits a manifest, it publishes a new one. That's the entire reason time travel is possible — history is append-only by design.
Two less-known properties. First, filenames inside a manifest are stored encrypted; they only become readable once you hold the depot key, which Steam hands out per-depot after checking your licenses. A manifest without its depot key tells you how many files exist and how big they are, but not what they're called. Second, manifests get cached locally: the Steam client keeps them in steamapps/depotcache/ as .manifest files, and DepotDownloader keeps its own copies in a hidden .DepotDownloader/ folder inside your download directory — that folder is also where it remembers which manifest your files currently correspond to. Don't delete it if you want fast updates; more on that in a second.
02The chunk pipeline
Game files don't travel as files. They're sliced into chunks of about 1 MB, and each chunk is independently compressed, then encrypted with the depot key (AES-256), then parked on the CDN addressable by its hash. When you download "a file", the client is really collecting a shopping list of chunk hashes from the manifest, fetching each from whichever content server answers fastest, decrypting, decompressing and stitching them at the right offsets.
This design quietly explains a lot of observable behaviour:
- Resume works for free — progress is just "which chunks do I have"; killing the process at 92% costs you at most the chunks in flight.
- Identical data deduplicates — two files sharing content share chunks, and an unchanged file across versions is the same chunk list.
- Compression evolves under your feet — Valve historically used LZMA-family compression and began rolling out zstd; that's why DepotDownloader 3.4.0's headline change was zstd support, and why ancient versions of the tool suddenly can't decode fresh depots. When downloads break after years of working, update the tool first.
03Why updating an existing folder is so fast
Here's my favourite part of the source. When you download into a directory that already holds an older build, DepotDownloader loads the cached old manifest from .DepotDownloader/ and diffs it against the target manifest, chunk by chunk. Chunks that already exist on your disk — even if they've moved to a different offset or a different file — are copied locally instead of downloaded. Only genuinely new chunks touch the network. It's the same trick the Steam client's updater does, and it means "downgrade, test, re-upgrade" cycles cost a fraction of the full download each way.
.DepotDownloader/ folder and you lose that superpower until the next full pass.
04Request codes, mechanically
Since May 2022, possessing a manifest ID is necessary but not sufficient. Before the CDN will serve a manifest, the client must call GetManifestRequestCode over the authenticated Steam connection, passing four things: the depot, the app, the manifest ID, and the branch it claims the manifest belongs to. Steam answers with a short-lived numeric token — or with zero, which is a refusal. The CDN checks the token on the manifest request; no token, HTTP 401, end of story.
The codes rotate quickly — DepotDownloader treats one as fresh for five minutes before re-requesting, which matches how the official client behaves. They're issued per-manifest, gated on the asking account's entitlement. That combination is precisely engineered to kill every workaround people first think of: a leaked code dies in minutes, and a code can't be requested for you by an account that doesn't pass the same checks Steam applies to yours.
One genuinely useful nugget hides in DepotDownloader's own error path: when a code is refused for an anonymous session, the tool prints a suggestion to retry with -username — because anonymous accounts get an extra-restricted view of manifest history, even for free apps. If your dedicated-server downgrade fails anonymously, logging in with any account that has the (free) license is the first thing to try.
05Who gets a code — the rules as we know them
Valve has never documented the policy, so what follows is the community's empirical map — assembled from SteamDB's analysis, the long-running discussion #573, and my own probes:
| Manifest | Code issued? | Why |
|---|---|---|
| Latest, public branch | YES | The baseline — this is what the Steam client itself needs. |
| Referenced by any active branch | YES | "Valid in appinfo" — the key rule. Betas and password-protected branches count. |
| Recently superseded | OFTEN | A grace window exists; its size varies by app and isn't published. |
| Old, unreferenced by any branch | USUALLY NOT | Nothing in appinfo vouches for it. This is where deep history died in January 2025. |
| Anything, if the developer opted to block old versions | NO | Per-app developer switch; overrides the grace window. |
| Anything, anonymous session | STRICTER | Anonymous accounts see less history than logged-in owners of the same content. |
The branch parameter explains one bug-report classic, too: requesting a manifest with the wrong branch context can fail even when the manifest is alive — which is why DepotDownloader asks for the branch you specified, and why a build that lives in a beta branch should be requested via -branch, not bare -manifest. For the history of how these rules tightened over time, the status page keeps the timeline and my latest test results.
06Myths, debunked with mechanics
- "Use a VPN." The refusal is keyed to your account's entitlements, not your IP. The CDN doesn't even get asked — the zero comes from the Steam session itself.
- "Some fork bypasses it." A fork is still a client. It can change what it asks; it cannot change what the server answers. Forks claiming otherwise are replaying borrowed credentials or lying — see the safety page for why that ends badly.
- "SteamDB has the files, just download from there." SteamDB records metadata — manifest IDs, dates, sizes. It has never hosted depot content. The ID is a name, not a copy.
- "The manifest is gone / deleted." Almost certainly not — the document still exists; what's gone is Steam's willingness to issue you a ticket for it. Materially the same outcome, but it matters: policy could re-open tomorrow, deleted data couldn't. (I'm not betting on it. But it's happened for individual apps when developers re-enabled old builds.)
- "download_depot in the Steam console avoids all this." It's the same protocol underneath, same gate. The occasional discrepancies people report cut both ways and aren't a method, just noise worth two minutes of your time when desperate.
07What to do with all this
If you came here from a 401: walk the diagnostic tree — owning account instead of anonymous, -branch if the build lives in one, ID sanity checks — then check the status page, and accept that nothing client-side flips a server-side zero. If you're here before downloading: archive the manifests you care about now — a manifest that gets a code today is one policy change from never getting one again. And if you're building tooling of your own, SteamKit2 exposes the same GetManifestRequestCode call DepotDownloader uses; the steamctl implementation discussion is a decent cross-language reference for the handshake.
The workflow this page underpins lives in the downgrade guide; the flags live in the CLI reference. And when the rules shift again — they will — the status banner moves first.