zlib compressobj flush() Ends the Stream (tested)

compressobj().flush() sounds like flushing a file buffer — getting pending bytes out so you can keep going. We measured what actually happens when you call it with no argument: the stream is over, permanently, and the next compress() call raises an error.

1. flush() with no argument finishes the stream

import zlib

c = zlib.compressobj()
out1 = c.compress(b"hello")
out2 = c.flush()
len(out1 + out2)
13

c.compress(b"world")
Traceback (most recent call last):
zlib.error: Error -2 while compressing data: inconsistent stream state

Measured: flush() called with no argument defaults to zlib.Z_FINISH, which writes the final compressed block and closes out the stream. The object isn't reset or reusable afterward — calling compress() again raises zlib.error: ... inconsistent stream state, and calling flush() a second time raises the identical error for the same reason.

2. Z_SYNC_FLUSH is the one that lets you keep compressing

c2 = zlib.compressobj()
out1 = c2.compress(b"hello ")
out2 = c2.flush(zlib.Z_SYNC_FLUSH)
out3 = c2.compress(b"world")
out4 = c2.flush()
zlib.decompress(out1 + out2 + out3 + out4)
b'hello world'

Measured: passing zlib.Z_SYNC_FLUSH explicitly pushes out all pending compressed data (useful for a streaming protocol where the other end needs bytes now) while leaving the compressor object usable — compress() works fine afterward, and a final no-argument flush() at the very end correctly closes the stream. The round-trip decompresses back to the exact original bytes.

3. Why the name is misleading

Per the Python zlib docs, flush([mode]) takes an optional mode that defaults to Z_FINISH — and Z_FINISH is explicitly documented to end the compressed stream. Unlike io module flush() methods (which push buffered bytes out without ending anything), zlib's default flush() is a one-way, irreversible operation on the object, not a lightweight "send what you have so far."

4. What to actually do

If you need to push out compressed data mid-stream and keep compressing afterward (e.g. a chunked HTTP response, a long-lived socket), call flush(zlib.Z_SYNC_FLUSH) or flush(zlib.Z_FULL_FLUSH), never bare flush(), until the very last chunk. Only call plain flush() (or equivalently flush(zlib.Z_FINISH)) once, when you're actually done and want to finalize the stream — treat the compressobj as single-use after that call.

Frequently asked questions

Does compressobj().flush() let you keep compressing afterward?

No — we measured flush() with no argument (which defaults to Z_FINISH) ending the stream permanently. The next compress() call raises zlib.error: inconsistent stream state.

What flush mode lets you push out data without ending the stream?

We measured flush(zlib.Z_SYNC_FLUSH) working correctly — it flushes pending compressed bytes while leaving the compressor object usable for further compress() calls.

Why does zlib's flush() behave differently from file-object flush()?

Based on the Python docs, zlib's flush() takes an optional mode argument that defaults to Z_FINISH, which explicitly ends the stream — unlike io module flush() methods, which just push buffered bytes without closing anything.

Can you reuse a compressobj after calling flush() with no argument?

No — we measured both compress() and a second flush() call on the same object raising the identical "inconsistent stream state" error once the default Z_FINISH flush has run.

How do I correctly flush mid-stream when compressing data incrementally?

We'd call flush(zlib.Z_SYNC_FLUSH) (or Z_FULL_FLUSH) for every intermediate flush, and only call plain flush() once at the very end to finalize the stream.

Written with AI assistance. Measured on 2026-10-03 with Python 3.13.5's built-in zlib module: called compressobj().flush() with no argument (the default) and then tried compress() and flush() again on the same object, comparing against calling flush(zlib.Z_SYNC_FLUSH) instead. PlainHeaders is our extension; Python's zlib module is built in.