question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

GZip Middleware Throws "Response content longer than Content-Length" when given a 304 empty-body response

See original GitHub issue

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn’t find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google “How to X in FastAPI” and didn’t find any information.
  • I already read and followed all the tutorial in the docs and didn’t find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

from typing import Awaitable, Callable

from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
from starlette.requests import Request

app = FastAPI()


@app.middleware("http")
async def noop_middleware(request: Request, call_next: Callable[[Request], Awaitable]):
    return await call_next(request)


@app.get("/", status_code=304)
def youve_seen_this_before():
    pass


app.add_middleware(GZipMiddleware)

Description

curl -sH “Accept-Encoding: gzip” localhost:8000

This will reliably: a) Give the expected 304 empty response. b) Show a stack trace “Response content longer than Content-Length”

The root cause I believe is the base middleware (in this example the noop one) creates a StreamingResponse for what is ultimately an empty response, it consists of two streaming chunks (“”, more=True), (“”, more=False); which bypasses the minimum length check in the GZip middleware.

GZip then compresses the ‘nothing’ resulting in the GZip minimum boilerplate, but an expected content length of 0 then throws. This is post-response so the client wont see the error but the server will.

Operating System

Linux, macOS

Operating System Details

Don’t think this is relevant.

FastAPI Version

0.63.0

Python Version

3.8.10

Additional Context

This is actually the root cause of issue: https://github.com/tiangolo/fastapi/issues/2818

In the case of that issue the trigger is the StaticFiles mount has not-modified support, and on getting a non-modified static resource returns a 304. I suspect the original issue reporter stopped running into it either as a by-product of not getting 304 as often, or alternatively changing their middleware so as not to create the StreamingResponse.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
tiangolocommented, Jul 14, 2022

This can be reproduced even without the GzipMiddleware:

from fastapi import FastAPI

app = FastAPI()


@app.get("/", status_code=204)
def endpoint():
    print("Oh, hi mark")

More details in this Starlette issue: https://github.com/encode/starlette/issues/1764

I’m fixing it on Starlette here: https://github.com/encode/starlette/pull/1765

And I’m fixing it on FastAPI here: https://github.com/tiangolo/fastapi/pull/5145

It will be available in the next version, released in some hours, FastAPI 0.79.0 🎉

1reaction
Kludexcommented, Nov 9, 2022

This can be reproduced even without the GzipMiddleware:

from fastapi import FastAPI

app = FastAPI()


@app.get("/", status_code=204)
def endpoint():
    print("Oh, hi mark")

More details in this Starlette issue: encode/starlette#1764

I’m fixing it on Starlette here: encode/starlette#1765

And I’m fixing it on FastAPI here: #5145

It will be available in the next version, released in some hours, FastAPI 0.79.0 tada

Those 2 are different issues.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ASP.NET Core Compression Middleware - Empty Reponse
1 Answer 1 ... And response on question is: You need to update context.Response.Headers["Content-Length"] with actual compressed buffer length.
Read more >
fasthttp - Go Packages
ErrBodyTooLarge is returned if either request or response body exceeds the given limit. View Source var ErrContentEncodingUnsupported = errors.New("unsupported ...
Read more >
Changelog — aiohttp 3.7.4 documentation
Server doesn't send Content-Length for 1xx or 204 #4901 ... Made cython HTTP parser set Reason-Phrase of the response to an empty string...
Read more >
waitress 2.1.2 documentation - The Pylons Project
Waitress is meant to be a production-quality pure-Python WSGI server with very ... send Transfer-Encoding or Content-Length for 1xx, 204, or 304 responses, ......
Read more >
https://web2.qatar.cmu.edu/~liginlal/angular/my-ap...
statusCode` if `err.status` is invalid - Set response headers from ... detection of zero-length body without `Content-Length` - deps: accepts@~1.2.9 - deps: ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found