cloudflare/pingora · error · pingora_error::Error
ERR_RESPONSE_TOO_LARGE
ERR_RESPONSE_TOO_LARGE
Error message
writing data of size {} bytes would exceed max file size of {} bytes What it means
While streaming a cacheable response, pingora counts body bytes against the cache's max_file_size_bytes limit (set via session.cache.set_max_file_size_bytes / cache options) before writing to storage. For responses without Content-Length (chunked), the size is only known mid-transfer; when the running total would exceed the cap, pingora marks the asset uncacheable (NoCacheReason::ResponseTooLarge) and returns ERR_RESPONSE_TOO_LARGE, aborting the in-flight request/response mid-transfer rather than caching a partial file. The nested expect additionally panics if size tracking reports an overflow with no limit configured (a framework-level inconsistency).
Source
Thrown at pingora-proxy/src/proxy_cache.rs:715
}
HttpTask::Body(data, end_stream) | HttpTask::UpgradedBody(data, end_stream) => {
// It is not normally advisable to cache upgraded responses
// e.g. they are essentially close-delimited, so they are easily truncated
// but the framework still allows for it
match data {
Some(d) => {
if session.cache.enabled() {
// TODO: do this async
// fail if writing the body would exceed the max_file_size_bytes
let body_size_allowed =
session.cache.track_body_bytes_for_max_file_size(d.len());
if !body_size_allowed {
debug!("chunked response exceeded max cache size, remembering that it is uncacheable");
session
.cache
.response_became_uncacheable(NoCacheReason::ResponseTooLarge);
return Error::e_explain(
ERR_RESPONSE_TOO_LARGE,
format!(
"writing data of size {} bytes would exceed max file size of {} bytes",
d.len(),
session.cache.max_file_size_bytes().expect("max file size bytes must be set to exceed size")
),
);
}
// this will panic if more data is sent after we see end_stream
// but should be impossible in real world
let miss_handler = session.cache.miss_handler().unwrap();
miss_handler.write_body(d.clone(), *end_stream).await?;
if *end_stream {
self.finish_miss_handler_best_effort(session, ctx).await;
}
}View on GitHub (pinned to 0046038bd4)
Solutions
- Raise the max file size (session.cache.set_max_file_size_bytes / your cache filter's max_file_size_bytes option) above the largest body you intend to cache
- Disable caching for routes serving arbitrarily large files (bypass cache in the request filter), so the mid-transfer abort path never engages
- Ensure origins send Content-Length where possible — oversize responses with a known length are demoted to uncacheable without failing the request
- If you never configured a limit but see this path, fix the CacheConf/session setup so tracking and limit stay consistent (otherwise the inner expect panics)
Example fix
// before: small cap while proxying large artifacts — mid-stream abort
session.cache.set_max_file_size_bytes(8 * 1024 * 1024);
// after: size the cap to real bodies, or bypass cache for large-file routes
session.cache.set_max_file_size_bytes(512 * 1024 * 1024);
// or, in the request cache filter:
// if session.req_header().uri.path().starts_with("/downloads/") {
// session.cache.bypassing() /* disable for this session */;
// } Defensive patterns
Strategy: validation
Validate before calling
// In request_cache_filter: bypass cache for known-large routes
async fn request_cache_filter(session: &mut Session, ctx: &mut ()) -> Result<()> {
if session.req_header().uri.path().starts_with("/downloads/") {
session.cache.bypassing(); // or disable(NoCacheReason::Deferred)
}
Ok(())
}
// Where sizes are known up front, compare Content-Length to the cap before enabling tracking
if let Some(len) = upstream_content_length {
if Some(len) > session.cache.max_file_size_bytes() {
session.cache.disable(NoCacheReason::ResponseTooLarge);
}
} Try / catch
// This is a Result error, not a panic: handle it in the ProxyHttp failure callback
async fn fail_to_proxy(&self, _s: &mut Session, e: &Error, _ctx: &mut ()) -> bool {
if e.etype() == Some(&pingora_error::ErrorType::new("ResponseTooLarge"))
|| e.to_string().contains("ERR_RESPONSE_TOO_LARGE") {
// deterministic policy failure — do NOT retry; log and adjust cache config
tracing::warn!("response exceeded cache max_file_size_bytes: {e}");
return false;
}
true // default handling for transient errors
} Prevention
- Size max_file_size_bytes from your 99.9th-percentile response size, not the average
- Exclude known-large routes from caching via the request cache filter
- Prefer origins that send Content-Length — oversize responses with known length bypass cache instead of aborting mid-stream
- Alert on ERR_RESPONSE_TOO_LARGE: it fails the client response, it does not merely skip caching
When it happens
Trigger: cache_http_task handling HttpTask::Body with session.cache.enabled() and a max_file_size_bytes cap configured, when the next chunk pushes the streamed body over the cap — typically chunked responses whose size wasn't knowable from headers (Content-Length-bearing oversize responses are caught earlier and merely bypass cache).
Common situations: Default/low max_file_size_bytes with large downloads (ISOs, models, video) and cache enabled globally; artifact/download endpoints accidentally covered by the cache policy; origins switching from Content-Length to chunked after an upgrade.
Related errors
- must have read body buf
- No tls feature was specified
- cache_key_callback must be implemented when caching is enabl
- invalid argument
- non-pathname unix sockets not supported as peer
AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16).
Data as JSON: /api/errors/77de866b17aa8ae3.
Report an issue: GitHub.