You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Java][IPC] AbstractCompressionCodec.compress() writes prefix=0 for empty buffers, incompatible with C++/Python readers #1196
When a buffer has writerIndex == 0 (e.g., a string column where all values
are empty string ""), AbstractCompressionCodec.compress() writes an 8-byte
buffer with uncompressed_length = 0 as a "shortcut for empty buffer":
if (uncompressedBuffer.writerIndex() == 0L) {
// shortcut for empty buffercompressedBuffer.setLong(0, 0); // prefix = 0
...
}
This has been present since the initial implementation (ARROW-11899, 2021).
The Java decompress() handles this correctly (if size==0 return empty),
but C++ and Python Arrow readers do not recognize prefix=0. They attempt
to decompress 0 bytes of data, which fails:
C++ (Arrow 1.0.0 ~ latest): IOError: Lz4 compressed input contains less than one frame
PyArrow 21.0: same error
Reproduction
Write an Arrow IPC stream with LZ4_FRAME (or ZSTD) compression where one
string column has all values = "" (empty string, not null). The string data
buffer has writerIndex = 0, triggering the empty buffer path.
My plan is to change the empty-buffer path in AbstractCompressionCodec.compress() to write the -1 (NO_COMPRESSION_LENGTH) sentinel instead of 0, since -1 is the value C++ and PyArrow already recognize as an uncompressed buffer. I'd keep the existing decompressedLength == 0 branch in decompress() so Java can still read older streams that were written with the 0 prefix.
Does that direction sound right, or would you rather drop the empty-buffer shortcut entirely and let the normal uncompressed fallback handle it? Once you confirm, I'll open a PR with a round-trip test covering an all-empty-string column.
Activity
PG1204 commentedon Jul 22, 2026
Hi @zgdgod , I'd like to pick this up.
My plan is to change the empty-buffer path in AbstractCompressionCodec.compress() to write the -1 (NO_COMPRESSION_LENGTH) sentinel instead of 0, since -1 is the value C++ and PyArrow already recognize as an uncompressed buffer. I'd keep the existing decompressedLength == 0 branch in decompress() so Java can still read older streams that were written with the 0 prefix.
Does that direction sound right, or would you rather drop the empty-buffer shortcut entirely and let the normal uncompressed fallback handle it? Once you confirm, I'll open a PR with a round-trip test covering an all-empty-string column.
Merge branch 'apache:main' into apachegh-1196-empty-buffer-compression
apacheGH-1196: Write NO_COMPRESSION_LENGTH sentinel for empty buffers…
apacheGH-1196: Write NO_COMPRESSION_LENGTH sentinel for empty buffers…
apacheGH-1196: Write NO_COMPRESSION_LENGTH sentinel for empty buffers…