{"record":{"id":"77de866b17aa8ae3","repo":"cloudflare/pingora","slug":"err-response-too-large","errorCode":"ERR_RESPONSE_TOO_LARGE","errorMessage":"writing data of size {} bytes would exceed max file size of {} bytes","messagePattern":"writing data of size (.+?) bytes would exceed max file size of (.+?) bytes","errorType":"error_code","errorClass":"pingora_error::Error","httpStatus":null,"severity":"error","filePath":"pingora-proxy/src/proxy_cache.rs","lineNumber":715,"sourceCode":"            }\n            HttpTask::Body(data, end_stream) | HttpTask::UpgradedBody(data, end_stream) => {\n                // It is not normally advisable to cache upgraded responses\n                // e.g. they are essentially close-delimited, so they are easily truncated\n                // but the framework still allows for it\n                match data {\n                    Some(d) => {\n                        if session.cache.enabled() {\n                            // TODO: do this async\n                            // fail if writing the body would exceed the max_file_size_bytes\n                            let body_size_allowed =\n                                session.cache.track_body_bytes_for_max_file_size(d.len());\n                            if !body_size_allowed {\n                                debug!(\"chunked response exceeded max cache size, remembering that it is uncacheable\");\n                                session\n                                    .cache\n                                    .response_became_uncacheable(NoCacheReason::ResponseTooLarge);\n\n                                return Error::e_explain(\n                                    ERR_RESPONSE_TOO_LARGE,\n                                    format!(\n                                        \"writing data of size {} bytes would exceed max file size of {} bytes\",\n                                        d.len(),\n                                        session.cache.max_file_size_bytes().expect(\"max file size bytes must be set to exceed size\")\n                                    ),\n                                );\n                            }\n\n                            // this will panic if more data is sent after we see end_stream\n                            // but should be impossible in real world\n                            let miss_handler = session.cache.miss_handler().unwrap();\n\n                            miss_handler.write_body(d.clone(), *end_stream).await?;\n                            if *end_stream {\n                                self.finish_miss_handler_best_effort(session, ctx).await;\n                            }\n                        }","sourceCodeStart":697,"sourceCodeEnd":733,"githubUrl":"https://github.com/cloudflare/pingora/blob/0046038bd402bc82912da862dadf9a479f31e9f1/pingora-proxy/src/proxy_cache.rs#L697-L733","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","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)"],"exampleFix":"// before: small cap while proxying large artifacts — mid-stream abort\nsession.cache.set_max_file_size_bytes(8 * 1024 * 1024);\n\n// after: size the cap to real bodies, or bypass cache for large-file routes\nsession.cache.set_max_file_size_bytes(512 * 1024 * 1024);\n// or, in the request cache filter:\n// if session.req_header().uri.path().starts_with(\"/downloads/\") {\n//     session.cache.bypassing() /* disable for this session */;\n// }","handlingStrategy":"validation","validationCode":"// In request_cache_filter: bypass cache for known-large routes\nasync fn request_cache_filter(session: &mut Session, ctx: &mut ()) -> Result<()> {\n    if session.req_header().uri.path().starts_with(\"/downloads/\") {\n        session.cache.bypassing(); // or disable(NoCacheReason::Deferred)\n    }\n    Ok(())\n}\n\n// Where sizes are known up front, compare Content-Length to the cap before enabling tracking\nif let Some(len) = upstream_content_length {\n    if Some(len) > session.cache.max_file_size_bytes() {\n        session.cache.disable(NoCacheReason::ResponseTooLarge);\n    }\n}","typeGuard":null,"tryCatchPattern":"// This is a Result error, not a panic: handle it in the ProxyHttp failure callback\nasync fn fail_to_proxy(&self, _s: &mut Session, e: &Error, _ctx: &mut ()) -> bool {\n    if e.etype() == Some(&pingora_error::ErrorType::new(\"ResponseTooLarge\"))\n        || e.to_string().contains(\"ERR_RESPONSE_TOO_LARGE\") {\n        // deterministic policy failure — do NOT retry; log and adjust cache config\n        tracing::warn!(\"response exceeded cache max_file_size_bytes: {e}\");\n        return false;\n    }\n    true // default handling for transient errors\n}","preventionTips":["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"],"tags":["rust","pingora","cache","response-size","max-file-size","streaming","chunked"],"backgroundTag":"response-size-limit-exceeded","analyzedSha":"0046038bd402bc82912da862dadf9a479f31e9f1","analyzedAt":"2026-08-16T21:33:22.341Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}