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
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.
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 contentOn the connection screen while the client fetches
/files/*from your server or file-server overrideDownloading completedOn the connection screen once the file stage finished
Failure downloading %s: %sIn 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 %sIn 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_httpFileServerProxyOnlyis on and the requester is outsidesv_proxyIPRangesNot 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.
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...(fromNetLibrary.cpp).It stays on
Downloading content, or progress is very slow: Continue with step 2: one player or everyoneIt stopped on
Fetching info from server...orConnecting to server...: Read the guide to Failed to get info from serverIt never leaves
Handshaking with server...: Open the server list guide (Direct Connect,/info.json)
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.
Only one or two players are slow: Read cause 4: the player’s own machine or network
Only players new to your server are slow: Read cause 1: too much data for your uplink
Everyone is slow, or nothing downloads at all: Continue with step 3: is your outbound link full?
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/sis in kibibytes per second: multiply by 0.008192 for Mbit/s). On Windows, useGet-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 withGet-Counter -ListSet *.sar -n DEV 1 10The rate is close to your uplink, and only while people download: Read cause 1: too much data for your uplink
The rate is low although players are stuck: Continue with step 4: do you already serve /files from a cache?
The rate stays pinned, nobody new is joining and no resource changed: Read what a DDoS looks like here
Do you already serve
/filesfrom a cache?In the server console,
fileserver_listprints each registered file server as<resource pattern> -> <url>and prints nothing when none is registered (the cookbook documents it;GetConfigurationMethod.cppimplements it). You can also searchserver.cfgforfileserver_add. With none registered, FXServer answers every file request itself. Also look forsv_httpFileServerProxyOnly.fileserver_listNothing is registered and
sv_httpFileServerProxyOnlyis not set: See when a cache in front of your files is the answerNothing is registered but
sv_httpFileServerProxyOnlyistrue: Read cause 3: the file server refuses the requestsA pattern is registered: Read cause 2: test and purge the cache
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.
Too much data for your uplink: many new players, large assets
Our inferenceUnless 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/swithsar -n DEV 1 10on 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 inresource.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.
The cache in front of your files is stale or set up wrongly
DocumentedThe 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 forinactive(10 minutes by default; the cookbook’sproxy_cache_pathleaves it unset) and evicts the least recently used data pastmax_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
$statusand$upstream_cache_status:MISSfor every player means the file is not kept,HITmeans it is, a403is the file server refusing (cause 3) and a404means the file server does not list that file for that resource. Or request one logged URL twice and read theX-Cache-Statusheader the cookbook sets. What to do
- Set
adhesive_cdnKey, drop any trailing slash from thefileserver_addURL, keep the query string in the cache key, sizeinactiveandmax_sizefor your files (the proxy-setup sample usesmax_size=20gandinactive=2h) and clear the cache when a resource changes.
The file server refuses the requests:
sv_httpFileServerProxyOnlyDocumentedsv_httpFileServerProxyOnly(defaultfalse) limits the file server to addresses insidesv_proxyIPRanges(default10.0.0.0/8 127.0.0.0/8 192.168.0.0/16 172.16.0.0/12).FilesHttpHandler.cppanswers everyone else with a403andHost %s is not allowed to access this endpoint., except for a file namedresource.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 istrue, confirm that afileserver_addpattern points at your cache and that the address your server sees the cache connect from is insidesv_proxyIPRanges. What to do
- Set it to
false, or add the cache’s address as your server sees it (the proxy-setup example usesset sv_proxyIPRanges "100.64.1.1/32"); behind a TLS terminator or similar layer, that is the layer’s address.
The player’s own machine or network
Owners reportThe 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.
Transfers are cut off partway
Owners reportPlayers’ 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.
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 listsres_http_handlerandresourceListwithout saying what they limit, andFilesHttpHandler.cppcalls 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_httpFileServerProxyOnlywith a correctsv_proxyIPRanges, remembering theresource.rpfexception. 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) withrxkB/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 10Who 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_httpFileServerProxyOnlyand a correctsv_proxyIPRangesmake the origin refuse other requesters, except forresource.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).
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 whethersv_httpFileServerProxyOnlyis set. - The transmitted rate during the stall (
sar -n DEV 1 10,txkB/s;Bytes Sent/secon Windows) and your plan’s uplink. - From one affected player, any error text shown on screen and the client log lines that mention
failure downloadingorCURL 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.
- FiveM cookbook: caching proxy for resource downloads (opens in a new tab)
- FiveM docs: proxy setup and connection process (opens in a new tab)
- FiveM docs: server commands and convars (opens in a new tab)
- FiveM docs: vanilla server setup (default port) (opens in a new tab)
- FiveM docs: client issues (opens in a new tab)
- FXServer: NetLibrary.cpp (connection stages) (opens in a new tab)
- FXServer: FilesHttpHandler.cpp (file server) (opens in a new tab)
- FXServer: GetConfigurationMethod.cpp (fileserver_add, fileserver_list) (opens in a new tab)
- FXServer: ResourceFilesComponent.cpp (resource.rpf, hashes) (opens in a new tab)
- FXServer: ResourceConfigurationCacheComponent.cpp (announced hashes) (opens in a new tab)
- FXServer: ResourceFileDatabase.cpp (when a package is rebuilt) (opens in a new tab)
- Client: ResourceCacheDeviceV2.cpp (SHA-1 check, retries) (opens in a new tab)
- Client: ResourceCacheDevice.cpp (V2 by default) (opens in a new tab)
- Client: ResourceCache.cpp (hash-named cache) (opens in a new tab)
- Client: CachedResourceMounter.cpp (file URLs) (opens in a new tab)
- nginx: proxy_cache_path (opens in a new tab)
- nginx: $upstream_cache_status (opens in a new tab)
- libcurl: error codes (CURLE_PARTIAL_FILE) (opens in a new tab)
- Cfx.re forum: a player’s post quoting the client log (anecdotal) (opens in a new tab)
- sar(1) manual: -n DEV fields (opens in a new tab)
- Microsoft Learn: network performance counters (opens in a new tab)
- Microsoft Learn: Get-Counter (counter names are localized) (opens in a new tab)
- tcpdump manual (opens in a new tab)
- pcap-filter(7): capture filters (opens in a new tab)
Server behaviour changes between builds. If your build prints something different, the build numbers above tell you what this page was checked against.