tursodatabase/turso · error · anyhow::Error
HTTP request length overflows
Error message
HTTP request length overflows: {content_length} What it means
TursoSyncServer parses HTTP by hand; request_end computes header_end + 4 + content_length with checked_add because, as the code comment states, the client fully controls Content-Length. This error fires when that sum would overflow usize - i.e. a client sent a Content-Length near usize::MAX (2^64-1 on 64-bit). It is a hardening guard against absurd headers rather than a normal failure.
Solutions
- Fix the client to send a Content-Length equal to the actual body byte count
- If exposing the server, front it with a proxy that enforces sane body-size limits
- When embedding the server, reject requests with Content-Length above a MAX_BODY_BYTES cap before reading the body
Example fix
// before (client): stale or wrapped length
let len = body.capacity(); // wrong: capacity, not len
write!(stream, "Content-Length: {len}\r\n\r\n")?;
// after: derive from the exact body
write!(stream, "Content-Length: {}\r\n\r\n", body.len())?;
stream.write_all(&body)?; Defensive patterns
Strategy: validation
Validate before calling
// Cap Content-Length before computing the body end:
const MAX_BODY_BYTES: usize = 64 * 1024 * 1024;
fn content_length_acceptable(content_length: usize) -> bool {
content_length <= MAX_BODY_BYTES
} Try / catch
let total_expected = match request_end(header_end, content_length) {
Ok(total) => total,
Err(err) if err.to_string().starts_with("HTTP request length overflows") => {
// hostile or broken client: answer 400 and close
return Err(err);
}
Err(err) => return Err(err),
}; Prevention
- Always derive Content-Length from the actual body length at send time
- Keep the checked_add in request_end intact - never plain addition on client-controlled values
- Front public deployments with a proxy enforcing body-size limits
When it happens
Trigger: handle_connection reads headers containing e.g. 'Content-Length: 18446744073709551615'; parse_content_length parses it into usize and (header_end + 4).checked_add(content_length) returns None in request_end.
Common situations: Port scanners or hostile probes sending overflow-style headers; buggy hand-rolled HTTP clients computing Content-Length with wrapped/negative arithmetic; fuzzers targeting the sync port.
Related errors
- database page number does not fit u32
- Empty request
- Invalid HTTP request
- Invalid request line
- Auth Token requires an HTTPS remote Turso URL unless the…
AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-08-20).
Data as JSON: /api/errors/0a693c631eeb9044.
Report an issue: GitHub.
Appendix: source
Thrown at cli/sync_server.rs:1265
let mut page = vec![0u8; PAGE_SIZE];
if conn.try_wal_watermark_read_page(1, &mut page, Some(max_frame))? {
Ok(db_size_from_page(&page) as u64)
} else {
Ok(0)
}
}
fn db_size_from_page(page: &[u8]) -> u32 {
u32::from_be_bytes(page[28..32].try_into().unwrap())
}
/// A client controls Content-Length, so the end of the body has to be
/// computed without trusting it to fit.
fn request_end(header_end: usize, content_length: usize) -> Result<usize> {
(header_end + 4)
.checked_add(content_length)
.ok_or_else(|| anyhow!("HTTP request length overflows: {content_length}"))
}
fn find_header_end(data: &[u8], start: usize) -> Option<usize> {
(start..data.len().saturating_sub(3)).find(|&i| &data[i..i + 4] == b"\r\n\r\n")
}
fn parse_content_length(headers: &str) -> Option<usize> {
for line in headers.lines() {
let lower = line.to_lowercase();
if lower.starts_with("content-length:") {
let value = line.split(':').nth(1)?.trim();
return value.parse().ok();
}
}
None
}
fn parse_http_request(data: &[u8]) -> Result<(String, String, Vec<u8>)> {View on GitHub (pinned to 492c4a71cd)