#3004·Rocket

Using Capped<TempFile> resets the network connection, Rocket doesn't notice.

Author: axokingCreated Jul 26, 2026Updated Jul 28, 2026
Labelstriage

Rocket Version

0.5.1

Operating System

CachyOS / Linux 7.1.4-1-cachyos

Rust Toolchain Version

rustc 1.96.1 (31fca3adb 2026-06-26) and rustc 1.99.0-nightly (f10db292a 2026-07-07)

What happened?

When using Capped<TempFile<'_>> as a function parameter, Rocket doesn't early-return if a limit is exceeded. Instead it just marks the Capped as incomplete (which you can check using .is_complete(), and lets you handle the too-large file the way you want.

This is great for my usecase because I need to handle a file upload and want to return different custom error messages if the file is e.g. too large.

However, if a limit is exceeded, Rocket doesn't send a Response. It calls the endpoint function, and it logs the Reponse as succesful, however it doesn't return data to the browser.

I tested this on Firefox, and Firefox shows an NS_ERROR_NET_RESET without a response body or response headers. Rocket however logs a status code and that the reponse succeeded.

During my testing, I did the following:

  • Opened localhost:8000
  • Selected a 80 KiB JPEG file, got a 200 OK (in the network analyzer from Firefox developer tools)
  • Selected a 40 MiB FLAC file, which is above the file size limit. Firefox showed a failed request (NS_ERROR_NET_RESET)

What's also interesting is that the request for the FLAC file was received twice by rocket. Maybe this is the browser automatically retrying or something, i don't know.

Test Case

rust
use rocket::{data::Capped, fs::{NamedFile, TempFile}, get, http::Status, launch, post, routes};

#[post("/upload_file", data = "<file>")]
fn upload_file(
	file: Capped<TempFile<'_>>
) -> (Status, &'static str) {
	if file.is_complete() {
		(Status::Ok, "Success!!!")
	}
	else {
		(Status::PayloadTooLarge, "The file was too large.")
	}
}

#[get("/")]
async fn index() -> NamedFile {
	NamedFile::open("index.html").await.unwrap()
}

#[launch]
fn rocket() -> _ {
	rocket::build()
		.mount("/", routes![index, upload_file])
}

Log Output

bash
-- configuration trace information --
   >> "address" parameter source: rocket::Config::default()
   >> "port" parameter source: rocket::Config::default()
   >> "workers" parameter source: rocket::Config::default()
   >> "max_blocking" parameter source: rocket::Config::default()
   >> "keep_alive" parameter source: rocket::Config::default()
   >> "ident" parameter source: rocket::Config::default()
   >> "ip_header" parameter source: rocket::Config::default()
   >> "limits" parameter source: rocket::Config::default()
   >> "temp_dir" parameter source: rocket::Config::default()
   >> "log_level" parameter source: `ROCKET_` environment variable(s)
   >> "shutdown" parameter source: rocket::Config::default()
   >> "cli_colors" parameter source: rocket::Config::default()
 Configured for debug.
   >> address: 127.0.0.1
   >> port: 8000
   >> workers: 12
   >> max blocking threads: 512
   >> ident: Rocket
   >> IP header: X-Real-IP
   >> limits: bytes = 8KiB, data-form = 2MiB, file = 1MiB, form = 32KiB, json = 1MiB, msgpack = 1MiB, string = 8KiB
   >> temp dir: /tmp
   >> http/2: true
   >> keep-alive: 5s
   >> tls: disabled
   >> shutdown: ctrlc = true, force = true, signals = [SIGTERM], grace = 2s, mercy = 3s
   >> log level: debug
   >> cli colors: true
 Routes:
   >> (index) GET /
   >> (upload_file) POST /upload_file
 Fairings:
   >> Shield (liftoff, response, singleton)
 Shield:
   >> X-Frame-Options: SAMEORIGIN
   >> Permissions-Policy: interest-cohort=()
   >> X-Content-Type-Options: nosniff
 Rocket has launched from http://127.0.0.1:8000

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:77
        received request: Request {
    method: GET,
    uri: /,
    version: HTTP/1.1,
    headers: {
        "host": "localhost:8000",
        "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:153.0) Gecko/20100101 Firefox/153.0",
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
        "accept-encoding": "gzip, deflate, br, zstd",
        "sec-gpc": "1",
        "connection": "keep-alive",
        "cookie": "team_id=5SUxbtcAMU3kN02W0S2SCwyQ0Lya0wwzoXmJPL4%3D",
        "upgrade-insecure-requests": "1",
        "sec-fetch-dest": "document",
        "sec-fetch-mode": "navigate",
        "sec-fetch-site": "none",
        "sec-fetch-user": "?1",
        "priority": "u=0, i",
    },
    body: Body(
        Empty,
    ),
}
GET / text/html:
   >> Matched: (index) GET /
   >> Outcome: Success(200 OK)

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:166
        sending response: Response {
    status: 200,
    version: HTTP/1.1,
    headers: {
        "content-type": "text/html; charset=utf-8",
        "server": "Rocket",
        "x-frame-options": "SAMEORIGIN",
        "permissions-policy": "interest-cohort=()",
        "x-content-type-options": "nosniff",
        "content-length": "526",
    },
    body: Body(
        Streaming,
    ),
}
   >> Response succeeded.

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:77
        received request: Request {
    method: POST,
    uri: /upload_file,
    version: HTTP/1.1,
    headers: {
        "host": "localhost:8000",
        "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:153.0) Gecko/20100101 Firefox/153.0",
        "accept": "*/*",
        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
        "accept-encoding": "gzip, deflate, br, zstd",
        "referer": "http://localhost:8000/",
        "content-type": "image/jpeg",
        "content-length": "78081",
        "origin": "http://localhost:8000",
        "sec-gpc": "1",
        "connection": "keep-alive",
        "cookie": "team_id=5SUxbtcAMU3kN02W0S2SCwyQ0Lya0wwzoXmJPL4%3D",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
        "priority": "u=0",
    },
    body: Body(
        Streaming,
    ),
}
POST /upload_file image/jpeg:
   >> Matched: (upload_file) POST /upload_file
   >> Outcome: Success(200 OK)

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:166
        sending response: Response {
    status: 200,
    version: HTTP/1.1,
    headers: {
        "content-type": "text/plain; charset=utf-8",
        "server": "Rocket",
        "x-frame-options": "SAMEORIGIN",
        "permissions-policy": "interest-cohort=()",
        "x-content-type-options": "nosniff",
        "content-length": "10",
    },
    body: Body(
        Streaming,
    ),
}
   >> Response succeeded.

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:77
        received request: Request {
    method: POST,
    uri: /upload_file,
    version: HTTP/1.1,
    headers: {
        "host": "localhost:8000",
        "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:153.0) Gecko/20100101 Firefox/153.0",
        "accept": "*/*",
        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
        "accept-encoding": "gzip, deflate, br, zstd",
        "referer": "http://localhost:8000/",
        "content-type": "audio/flac",
        "content-length": "40204828",
        "origin": "http://localhost:8000",
        "sec-gpc": "1",
        "connection": "keep-alive",
        "cookie": "team_id=5SUxbtcAMU3kN02W0S2SCwyQ0Lya0wwzoXmJPL4%3D",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
        "priority": "u=0",
    },
    body: Body(
        Streaming,
    ),
}
POST /upload_file audio/flac:
   >> Matched: (upload_file) POST /upload_file
   >> Data limit reached while reading the request body.
   >> Outcome: Success(413 Payload Too Large)

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:166
        sending response: Response {
    status: 413,
    version: HTTP/1.1,
    headers: {
        "content-type": "text/plain; charset=utf-8",
        "server": "Rocket",
        "x-frame-options": "SAMEORIGIN",
        "permissions-policy": "interest-cohort=()",
        "x-content-type-options": "nosniff",
        "content-length": "23",
    },
    body: Body(
        Streaming,
    ),
}
   >> Response succeeded.

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:77
        received request: Request {
    method: POST,
    uri: /upload_file,
    version: HTTP/1.1,
    headers: {
        "host": "localhost:8000",
        "user-agent": "Mozilla/5.0 (X11; Linux x86_64; rv:153.0) Gecko/20100101 Firefox/153.0",
        "accept": "*/*",
        "accept-language": "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
        "accept-encoding": "gzip, deflate, br, zstd",
        "referer": "http://localhost:8000/",
        "content-type": "audio/flac",
        "content-length": "40204828",
        "origin": "http://localhost:8000",
        "sec-gpc": "1",
        "connection": "keep-alive",
        "cookie": "team_id=5SUxbtcAMU3kN02W0S2SCwyQ0Lya0wwzoXmJPL4%3D",
        "sec-fetch-dest": "empty",
        "sec-fetch-mode": "cors",
        "sec-fetch-site": "same-origin",
        "priority": "u=0",
    },
    body: Body(
        Streaming,
    ),
}
POST /upload_file audio/flac:
   >> Matched: (upload_file) POST /upload_file
   >> Data limit reached while reading the request body.
   >> Outcome: Success(413 Payload Too Large)

--> /home/tom/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/rocket-0.5.1/src/server.rs:166
        sending response: Response {
    status: 413,
    version: HTTP/1.1,
    headers: {
        "content-type": "text/plain; charset=utf-8",
        "server": "Rocket",
        "x-frame-options": "SAMEORIGIN",
        "permissions-policy": "interest-cohort=()",
        "x-content-type-options": "nosniff",
        "content-length": "23",
    },
    body: Body(
        Streaming,
    ),
}
   >> Response succeeded.

Additional Context

index.html

xml
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<input type="file" id="fileinput">
	<button id="button">Upload</button>
</body>

<script>
	document.getElementById("button").addEventListener("click", () => {
		const file = document.getElementById("fileinput").files[0];

		fetch("/upload_file", {
			method: "POST",
			body: file
		}).then(resp => {
			console.log(resp)
		})
	})
</script>
</html>

System Checks

  • My bug report relates to functionality.
  • I have tested against the latest Rocket release or a recent git commit.
  • I have tested against the latest stable rustc toolchain.
  • I was unable to find this issue previously reported.