FiveM stuck downloading resources: why it is slow and how to speed it up

Updated

Verified against FXServer build 35245 (recommended), 37150 (latest), checked on 7 October 2026. Sources

VerdictNot evidence of a DDoS by itself

Look first at your uplink, how your files are served and the player’s own machine; a slow download alone does not show an attack.

FiveShield helps with part of this

Partly: FiveShield only matters for the server-side half, a cache in front of your files, and the plain nginx cache in the official cookbook applies the same mechanism.

A player stuck on Downloading content is waiting for files from your server or your file server. This page ranks three causes first: an uplink that many new players fill at once, a cache or file-server setting that rejects or corrupts requests, and the player’s own disk or network. A DDoS is possible, but this symptom cannot show one on its own.

Check first whether it is one player or everyone (step 2) and whether your outbound traffic is full while they wait (step 3). If the uplink is the limit, serve /files from a cache registered with fileserver_add, as the official cookbook describes; if you already run one, test it first (cause 2).

For this symptom, suspect a flood of file requests only when the addresses receiving your files are not your players.

Messages you may see

  • Downloading content

    On the connection screen while the client fetches /files/* from your server or file-server override

  • Downloading completed

    On the connection screen once the file stage finished

  • Failure downloading %s: %s

    In the error the client reports when a file keeps failing; the client log carries a related line, ResourceCacheDevice reporting failure downloading ...

  • %s hash %s does not match %s

    In the client log when a downloaded file fails its SHA-1 check

  • Host %s is not allowed to access this endpoint.

    In the 403 body from your file server when sv_httpFileServerProxyOnly is on and the requester is outside sv_proxyIPRanges

  • Not found. (missing requested file: %s/%s)

    In the 404 body from your file server when the requested file is neither one of the resource’s packaged files nor a streamed file

What it actually means

The client prints Downloading content once your server has accepted the connection, and Downloading completed when the client signals that the downloads are done (NetLibrary.cpp). They are progress lines, not errors; the UDP step, Fetching info from server..., starts after them.

The files come from GET /files/*, answered by your FXServer unless you registered a file server override with fileserver_add (proxy-setup documentation). FilesHttpHandler.cpp accepts GET only, answers for a resource’s packaged files (resource.rpf and any file_set archives, per ResourceFilesComponent.cpp) and its streamed files, and sends them from disk whether or not a connecting client matches.

The client looks each file up by SHA-1 in its own cache (files named cache_<hash>) and re-hashes the cached copy; only a missing or mismatching file is downloaded (ResourceCache.cpp, ResourceCacheDeviceV2.cpp). New players, players who cleared their cache and everyone after a resource change download the most.

A failed request is retried. By our reading of ResourceCacheDeviceV2.cpp, a file gets up to five attempts, waiting 1, 2, 4, 8 and 16 seconds after the failures at the default cl_rcdFailureBackoff of 500 (milliseconds), so one undeliverable file can hold up its resource for over half a minute before the client reports an error. We have not timed this on a live client.

Check this first (two minutes)

Four questions separate your server, your cache and the player’s machine.

  1. Which line is the connection screen stuck on?

    Ask for the exact text. Among the lines the client prints, these come in this order: Handshaking with server..., Downloading content, Downloading completed, Fetching info from server..., Connecting to server... (from NetLibrary.cpp).

  2. Is it one player, or everyone who joins?

    Have two or three players on different connections join together, including one who has never joined your server.

  3. Is your outbound link full while they wait?

    Read the transmitted rate on the public interface and compare it with your plan’s uplink (txkB/s is in kibibytes per second: multiply by 0.008192 for Mbit/s). On Windows, use Get-Counter -Counter '\Network Interface(*)\Bytes Sent/sec' -Continuous, in bytes per second (divide by 125,000 for Mbit/s). Counter names are translated on a non-English Windows and the English path then fails; list yours with Get-Counter -ListSet *.

    sar -n DEV 1 10
  4. Do you already serve /files from a cache?

    In the server console, fileserver_list prints each registered file server as <resource pattern> -> <url> and prints nothing when none is registered (the cookbook documents it; GetConfigurationMethod.cpp implements it). You can also search server.cfg for fileserver_add. With none registered, FXServer answers every file request itself. Also look for sv_httpFileServerProxyOnly.

    fileserver_list

Causes, ranked

Your own capacity and configuration come first, then the player’s side, then failing transfers, and the attack case last. The badge says where each claim comes from.

Ranked by what owners report most and how cheap each check is. That is an editorial order, not a statistic: nobody publishes a dataset of FiveM outage causes. Documented means official docs or the FXServer and txAdmin source. Owners report means forum threads and issue trackers. Our inference is our reasoning from documented facts, shown so you can check it.

  1. Too much data for your uplink: many new players, large assets

    Our inference

    Unless a file server override serves them, every file a new player lacks leaves your server through GET /files/*, sharing your uplink with the game traffic of everyone connected. Delivering a join wave takes at least (bytes per new player × new players) ÷ uplink. For illustration only: 40 new players pulling 1.5 GB each is 60 GB, about eight minutes at 1 Gbit/s with nothing else running.

    How to confirm

    While players wait, read txkB/s with sar -n DEV 1 10 on the public interface and compare it with your uplink. Then sort your started resources’ folders by size: a folder overstates what players receive (server scripts, for one, are not in resource.rpf), but one resource that dominates the list is where to look.

    What to do

    Move the files off the origin with a caching proxy registered by fileserver_add, as the official cookbook shows with nginx, and test it first (cause 2). Remove unused resources, swap oversized packs for lighter ones and keep updates out of peak hours. A cache does not shrink a file, and the server documentation lists no convar that speeds up the built-in file server.
  2. The cache in front of your files is stale or set up wrongly

    Documented

    The cookbook, published in 2019, calls adhesive_cdnKey “required to not get corrupted cache entries” and warns there is no hash-based cache invalidation, so clear the cache before you modify or restart a resource. The client rejects a file whose SHA-1 differs from the announced one (ResourceCacheDeviceV2.cpp), downloads it again and fails it after five attempts. By our reading, the client appends ?hash=<sha1> to its file URLs (CachedResourceMounter.cpp) and the server ignores that query (FilesHttpHandler.cpp): a cache keyed on the full URL, like the cookbook’s, stores a changed file as a new entry, while one told to ignore the query string keeps serving the old file. A cache can also forget files: nginx drops anything not requested for inactive (10 minutes by default; the cookbook’s proxy_cache_path leaves it unset) and evicts the least recently used data past max_size.

    How to confirm

    Join with a test account and read the cache’s access log, where the cookbook’s configuration prints each request with $status and $upstream_cache_status: MISS for every player means the file is not kept, HIT means it is, a 403 is the file server refusing (cause 3) and a 404 means the file server does not list that file for that resource. Or request one logged URL twice and read the X-Cache-Status header the cookbook sets.

    What to do

    Set adhesive_cdnKey, drop any trailing slash from the fileserver_add URL, keep the query string in the cache key, size inactive and max_size for your files (the proxy-setup sample uses max_size=20g and inactive=2h) and clear the cache when a resource changes.
  3. The file server refuses the requests: sv_httpFileServerProxyOnly

    Documented

    sv_httpFileServerProxyOnly (default false) limits the file server to addresses inside sv_proxyIPRanges (default 10.0.0.0/8 127.0.0.0/8 192.168.0.0/16 172.16.0.0/12). FilesHttpHandler.cpp answers everyone else with a 403 and Host %s is not allowed to access this endpoint., except for a file named resource.rpf. Turned on with no cache in front, or with the cache’s address outside the ranges, it refuses every other file, and the client retries each one before it gives up.

    How to confirm

    Look for it in server.cfg. If it is true, confirm that a fileserver_add pattern points at your cache and that the address your server sees the cache connect from is inside sv_proxyIPRanges.

    What to do

    Set it to false, or add the cache’s address as your server sees it (the proxy-setup example uses set sv_proxyIPRanges "100.64.1.1/32"); behind a TLS terminator or similar layer, that is the layer’s address.
  4. The player’s own machine or network

    Owners report

    The client writes each file to its cache folder, hashes it and renames it into the cache, and re-hashes cached files before reuse (ResourceCache.cpp, ResourceCacheDeviceV2.cpp). A slow or full disk, security software scanning new files or a poor line can slow those steps; that is our reasoning, and the official client-issues page ties antivirus only to launch problems, so this cause rests on replies in Cfx.re forum threads, not on documentation.

    How to confirm

    Have the player join another server, or yours from another network. If only yours is slow for them, look at your side; if every server is slow, it is their machine or line.

    What to do

    Free disk space, check whether security software or a URL filter scans or blocks new files, try another network with a VPN off and then on, and clear the client cache last, since everything is then downloaded again.
  5. Transfers are cut off partway

    Owners report

    Players’ threads on the Cfx.re forum quote client errors such as Failure downloading resource.rpf: transfer closed with 12324864 bytes remaining to read - CURL error code 18 (Transferred a partial file); libcurl documents code 18 as “A file transfer was shorter or larger than expected.” The line does not say who cut the transfer: your server, a proxy or cache in between, or the player’s network. The replies we read point at the player’s connection or machine and show no confirmed fix.

    How to confirm

    Get the log lines around the failure from an affected player, and see whether players on other networks hit it at the same moment. If several do, look at your side: uplink (cause 1), cache logs and timeouts (cause 2).

    What to do

    One player: their line (cause 4). Many at once: cut origin load (cause 1) and read your cache and proxy error logs for upstream timeouts or resets.
  6. A download flood

    Our inferenceThe DDoS case

    /files/* is a plain GET that FXServer answers for an existing file even when no connecting client matches (FilesHttpHandler.cpp), so a flood of file requests is technically possible. The documentation describes no per-address limit for it: its rate-limiter table lists res_http_handler and resourceList without saying what they limit, and FilesHttpHandler.cpp calls no limiter. Its frequency is unknown; nothing we read measures it.

    How to confirm

    Compare who receives your files with who is connected, and read your host’s graph (next section).

    What to do

    Put the files behind a cache and set sv_httpFileServerProxyOnly with a correct sv_proxyIPRanges, remembering the resource.rpf exception. If your host or a capture confirms an attack, follow the traffic spike guide.

What a DDoS looks like here

The attack that fits this symptom is a flood of file requests, and the symptom cannot show it: a join wave and a flood both fill your outbound link. What separates them is who receives the data; addresses that are not your players would change the verdict. A flood of packets aimed at your server is a different problem with a different signature (see the traffic spike guide).

What a DDoS looks like here

  • The outbound link stays full with no join wave behind it: no event, restart or changed resource, and your player count does not explain the volume.
  • A short capture shows many addresses receiving file traffic from your server that match no connected player. A cache’s access log shows the same from outside the game server.
  • Your host’s graph shows outbound volume your player count cannot explain. Export it before you change anything: hosts keep graphs for a limited time (see the traffic spike guide).

Evidence you can collect

  • Direction and rate on the public interface

    Download traffic leaves your machine: compare txkB/s (transmitted) with rxkB/s (received). A packet flood aimed at you shows as received packets (rxpck/s) and is a different problem. Capture a baseline on a quiet day.

    sar -n DEV 1 10
  • Who is receiving your files

    On Linux, a short capture of what your server sends from its TCP game port, which also serves /files (30120 by default; capturing may need elevated privileges). Read each destination and compare the addresses with your players from your own records: the documentation describes no built-in download log. Behind a cache or proxy you will see its address, not the players’: read its access log instead.

    tcpdump -n -i <iface> -c 2000 'tcp src port 30120'

What it does not look like

  • An outbound burst right after a restart, an update or an event with many new players is a join wave (cause 1), and it ends when the downloads end.
  • One slow player, or players on one network, points at the player’s side (cause 4). Low outbound traffic while players wait means bytes are not the limit (causes 2, 3 and 5).

When protection is, and is not, the answer

Here “protection” means a cache in front of /files: it keeps each file after the first request and answers repeats of the same URL itself. The official cookbook shows nginx; a managed CDN is another way to run it. This page has not measured any vendor’s cache, and everything below works with one you run yourself.

Protection is the answer when

  • The outbound link is full while many players download files they do not have yet, and the arithmetic in cause 1 says the uplink is the limit.
  • You have confirmed a flood of file requests from addresses that are not your players: a cache answers repeats of the same URL, and, with the cache registered by fileserver_add, sv_httpFileServerProxyOnly and a correct sv_proxyIPRanges make the origin refuse other requesters, except for resource.rpf.

Protection is not the answer when

  • One player, or players on one network, are slow: nothing in front of your server changes their disk, security software or line (cause 4).
  • Outbound traffic is low while players wait: the uplink is not the limit, and a layer in front of a rejected request (cause 3) or a stale cache (cause 2) hides the fault. Look at causes 4 and 5 instead.
  • The assets are huge: a cache does not shrink a file, so each file’s first download still crosses the link (cause 1).

FiveM anti-DDoS: how FiveShield works

Still stuck? What to post

Paste these when you ask a host or a community for help.

  • The exact connection-screen text and how long it stayed there.
  • Your FXServer build number, the output of fileserver_list, and whether sv_httpFileServerProxyOnly is set.
  • The transmitted rate during the stall (sar -n DEV 1 10, txkB/s; Bytes Sent/sec on Windows) and your plan’s uplink.
  • From one affected player, any error text shown on screen and the client log lines that mention failure downloading or CURL error code (search without case), and whether that player is slow on other servers (the official pages we checked do not give the log location).
  • If you run a cache, a few access-log lines with their $upstream_cache_status, and what changed right before it started.

Frequently asked questions

Is a slow resource download a sign of a DDoS?

Not on its own. A full uplink, a cache or file-server setting and the player’s machine all produce it, and a join wave and a flood look the same on your outbound link; only the addresses receiving the files tell them apart. A flood of file requests is technically possible, because /files/* serves an existing file to any GET request with no connecting client needed, but nothing we read measures how often it happens.

Do I need a CDN to speed up FiveM resource downloads?

No. A CDN is one way to run a cache. The official cookbook shows the same mechanism with nginx: fileserver_add, adhesive_cdnKey, and clearing the cache when a resource changes. Whether a managed cache is faster than your own, this page has not measured.

Why are only new players stuck, and does a restart make everyone download again?

The client keeps downloaded files in its own cache, named by SHA-1, and requests only the files it lacks or whose cached copy fails the hash check. Returning players fetch what changed and new players fetch everything (cause 1). By our reading of the server source (ResourceFilesComponent.cpp, ResourceFileDatabase.cpp, ResourceConfigurationCacheComponent.cpp), the server rebuilds a resource’s resource.rpf only when a file in it was added, removed or changed, and announces the SHA-1 of the package it holds, so a restart that touches no file should not make returning players download again. We have not tested this on a live server, nor compared a rebuilt package byte for byte.

Verified against, and sources

Verified against FXServer build 35245 (recommended), 37150 (latest), checked on 7 October 2026.

Server behaviour changes between builds. If your build prints something different, the build numbers above tell you what this page was checked against.