Problem
Python 3.13 introduced a regression where GzipFile.__del__ tries to flush to an already-closed BytesIO buffer, raising:
Exception ignored in: <gzip on 0x...>
File "/usr/local/lib/python3.13/gzip.py", line 373, in close
fileobj.write(self.compress.flush())
ValueError: I/O operation on closed file.
This happens when a client disconnects before the gzip-compressed response is fully written. Litestar's compression middleware closes the BytesIO buffer, but the GzipFile finalizer still tries to write to it.
Impact
- Errors spam the logs on every client disconnect
- When health check probes (
/healthz/) are affected, K8s kills the pod after liveness probe timeouts (exit code 137), causing intermittent 404/bad gateway from the load balancer
- Both replicas can fail simultaneously, causing total downtime
Fix
SafeGzipCompression in skrift/middleware/compression.py — a drop-in replacement for Litestar's GzipCompression that catches ValueError on close. Wired into all CompressionConfig usages in asgi.py.
Already implemented on the current branch.
Problem
Python 3.13 introduced a regression where
GzipFile.__del__tries to flush to an already-closedBytesIObuffer, raising:This happens when a client disconnects before the gzip-compressed response is fully written. Litestar's compression middleware closes the
BytesIObuffer, but theGzipFilefinalizer still tries to write to it.Impact
/healthz/) are affected, K8s kills the pod after liveness probe timeouts (exit code 137), causing intermittent 404/bad gateway from the load balancerFix
SafeGzipCompressioninskrift/middleware/compression.py— a drop-in replacement for Litestar'sGzipCompressionthat catchesValueErroron close. Wired into allCompressionConfigusages inasgi.py.Already implemented on the current branch.