ERROR

Root Cause Analysis: Why Nginx Fails with 'Invalid Chunked Response' from Upstream

Quick Fix Summary

TL;DR

Disable chunked transfer encoding with 'proxy_http_version 1.0' or buffer the entire response.

Nginx's HTTP/1.1 proxy module expects properly formatted chunked encoding from upstream servers. When upstream sends malformed chunk size headers or premature termination, Nginx rejects the response as invalid. This is a protocol violation that breaks the client connection.

Diagnosis & Causes

  • Upstream application sends malformed chunk size (non-hexadecimal).
  • Race condition between Content-Length and Transfer-Encoding headers.
  • Upstream server prematurely closes connection during chunked transfer.
  • Proxy buffering disabled while upstream uses chunked encoding.
  • Buggy application frameworks mishandling HTTP/1.1 chunked responses.
  • Recovery Steps

    1

    Step 1: Force HTTP/1.0 to Disable Chunked Encoding

    HTTP/1.0 doesn't support chunked transfer encoding. This forces simple response buffering.

    nginx
    location /api/ {
        proxy_pass http://backend;
        proxy_http_version 1.0;
        proxy_set_header Connection "";}
    2

    Step 2: Enable Full Response Buffering

    Buffer the entire upstream response before sending to client. This handles malformed chunking internally.

    nginx
    location /api/ {
        proxy_pass http://backend;
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
        proxy_busy_buffers_size 8k;}
    3

    Step 3: Debug Upstream Response with tcpdump

    Capture raw HTTP traffic to inspect malformed chunked encoding from upstream.

    bash
    sudo tcpdump -i any -A -s 0 'port 8080 and host backend_ip'
    # Look for chunk size lines like:
    # "Transfer-Encoding: chunked"
    # "\r\n" (empty line)
    # "1a" (hex chunk size)
    # "{data}"
    # "0\r\n\r\n" (termination)
    4

    Step 4: Validate Upstream Application Code

    Check application frameworks for proper chunked encoding implementation.

    python
    # Python Flask example - Ensure no manual Content-Length with chunked
    from flask import Response
    def stream_data():
        def generate():
            yield b"Hello "
            yield b"World"
        return Response(generate(), content_type='text/plain')
    # NOT: Response(data, headers={'Content-Length': '10'})
    5

    Step 5: Configure Upstream Timeouts and Retries

    Prevent race conditions from upstream timeouts during chunked transfer.

    nginx
    location /api/ {
        proxy_pass http://backend;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
        proxy_send_timeout 300s;
        proxy_next_upstream error timeout invalid_header http_500;}
    6

    Step 6: Patch Nginx with Custom Lua Handler

    Use OpenResty's Lua module to sanitize malformed chunked responses.

    nginx
    location /api/ {
        proxy_pass http://backend;
        header_filter_by_lua_block {
            ngx.header["Transfer-Encoding"] = nil
            ngx.header["Content-Length"] = #ngx.arg[1]
        }
        body_filter_by_lua_block {
            ngx.arg[1] = ngx.arg[1]:gsub("\\r\\n[0-9a-fA-F]+\\r\\n", "")
        }}

    Architect's Pro Tip

    "The error often surfaces during zero-downtime deployments when old and new application versions simultaneously proxy traffic with different HTTP semantics."

    Frequently Asked Questions

    Why does Nginx reject chunked encoding but other proxies don't?

    Nginx strictly follows RFC 7230 Section 4.1 for chunked encoding validation. Some proxies are more lenient, accepting malformed responses that eventually cause client-side issues.

    Can this error cause data corruption or just connection drops?

    Primarily connection drops (502 Bad Gateway). However, if buffering is partial, clients may receive truncated responses leading to logical data corruption.

    Is this more common with specific programming languages or frameworks?

    Yes. Older Java servlet containers, misconfigured Python ASGI servers, and custom C++ HTTP implementations frequently produce invalid chunked boundaries during streaming responses.

    Related Nginx Guides