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

  1. 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
  2. Disable caching for routes serving arbitrarily large files (bypass cache in the request filter), so the mid-transfer abort path never engages
  3. Ensure origins send Content-Length where possible — oversize responses with a known length are demoted to uncacheable without failing the request
  4. 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

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


AI-assisted analysis of cloudflare/pingora@0046038bd4 (2026-08-16). Data as JSON: /api/errors/77de866b17aa8ae3. Report an issue: GitHub.