{"record":{"id":"5c9ff804bff894cc","repo":"neondatabase/neon","slug":"file-size-request-len-exceeds-max-max-len","errorCode":null,"errorMessage":"File size {request_len} exceeds max {max_len}","messagePattern":"File size (.+?) exceeds max (.+?)","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"endpoint_storage/src/app.rs","lineNumber":93,"sourceCode":"        .status(StatusCode::OK)\n        .header(CONTENT_TYPE, APPLICATION_OCTET_STREAM)\n        .body(Body::from_stream(stream))\n        .map_err(|e| internal_error(e, path, \"reading response\"))\n}\n\n// Best solution for files is multipart upload, but remote_storage doesn't support it,\n// so we can either read Bytes in memory and push at once or forward BodyDataStream to\n// remote_storage. The latter may seem more peformant, but BodyDataStream doesn't have a\n// guaranteed size() which may produce issues while uploading to s3.\n// So, currently we're going with an in-memory copy plus a boundary to prevent uploading\n// very large files.\nasync fn set(S3Path { path }: S3Path, state: State, bytes: Bytes) -> Result {\n    info!(%path, \"uploading\");\n    let request_len = bytes.len();\n    let max_len = state.max_upload_file_limit;\n    if request_len > max_len {\n        return Err(bad_request(\n            anyhow!(\"File size {request_len} exceeds max {max_len}\"),\n            \"uploading\",\n        ));\n    }\n\n    let cancel = state.cancel.clone();\n    let fun = async || {\n        let stream = bytes_to_stream(bytes.clone());\n        state\n            .storage\n            .upload(stream, request_len, &path, None, &cancel)\n            .await\n    };\n    retry(\n        fun,\n        TimeoutOrCancel::caused_by_cancel,\n        WARN_THRESHOLD,\n        MAX_RETRIES,\n        \"uploading\",","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/neondatabase/neon/blob/8f60b04da47ffefe0e52bda2440134b42874eb75/endpoint_storage/src/app.rs#L75-L111","documentation":"endpoint_storage's PUT handler buffers the whole request body in memory and rejects uploads larger than the configured max_upload_file_limit, returning a 400 with this message. The limit exists because remote_storage has no multipart support, so the service must hold the entire object in memory; the default is 100 MiB (100 * 1024 * 1024), configurable via the max_upload_file_limit field in the service's JSON config.","triggerScenarios":"PUT-ing a body whose length exceeds state.max_upload_file_limit to the endpoint_storage HTTP endpoint (e.g. an extension artifact upload). The size check runs before any storage call and returns bad_request.","commonSituations":"Uploading large custom extensions or binaries above 100 MiB to a deployment running the default limit; a config that lowered the limit for memory protection; clients that do not check Content-Length against the service's limit before sending.","solutions":["Reduce the upload size below the service's limit","Raise max_upload_file_limit in the endpoint_storage JSON config and restart the service (mind the memory footprint — bodies are held in memory)","Split or compress the artifact so it fits under the configured bound"],"exampleFix":"// endpoint_storage config (main.rs reads JSON config)\n// before\n{ \"pemfile\": \"/pem\", \"listen\": \"0.0.0.0:51243\", \"storage_kind\": {\"S3\": {...}} }\n// after\n{ \"pemfile\": \"/pem\", \"listen\": \"0.0.0.0:51243\", \"max_upload_file_limit\": 524288000, \"storage_kind\": {\"S3\": {...}} }","handlingStrategy":"validation","validationCode":"// Client-side check before PUT: know the service's limit and your body size\nlet body_len = bytes.len();\nif body_len > MAX_UPLOAD_FILE_LIMIT {\n    return Err(anyhow::anyhow!(\n        \"body is {body_len} bytes, service limit is {MAX_UPLOAD_FILE_LIMIT}; split or raise max_upload_file_limit\"\n    ));\n}\n// or, when the limit is discoverable, compare Content-Length against it before sending","typeGuard":null,"tryCatchPattern":"match resp.status() {\n    StatusCode::BAD_REQUEST if body_contains(&resp, \"exceeds max\").await => {\n        // permanent: do not retry; shrink payload or raise the server's max_upload_file_limit\n        return Err(UploadTooLarge.into());\n    }\n    s if s.is_server_error() => { /* retryable */ }\n    _ => {}\n}","preventionTips":["Agree on an explicit size contract (the server's max_upload_file_limit) with clients before uploading","Check file size locally before starting a large PUT to avoid buffering 100+ MiB for a guaranteed 400","Remember the whole body is held in server memory when tuning the limit"],"tags":["endpoint-storage","upload","size-limit","http-400","rust"],"backgroundTag":"request-body-too-large","analyzedSha":"8f60b04da47ffefe0e52bda2440134b42874eb75","analyzedAt":"2026-08-16T23:39:28.135Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}