Observed behavior
- The server cannot read one message from a stream.
- The server shows this error for each read of the message:
[ERR] Received an error looking up message for consumer '$G > STREAM_NAME > CONSUMER_NAME': compression algorithm not known
- All consumers of the stream stop at the sequence before this message.
- The consumers do not move to the next sequence.
- A read of the message with
nats stream get gives error 10037, "no message found".
- A delete of the message with
nats stream rmm gives error 10057, "compression algorithm not known".
- The data on the disk is correct. The server cannot decode it.
Root cause:
The filestore uses the first bytes of a block to find the compression metadata.
The function CompressionInfo.UnmarshalMetadata (server/filestore.go) does this test
(here in current main):
if b[0] != 'c' || b[1] != 'm' || b[2] != 'p' {
return 0, nil
}
c.Algorithm = StoreCompression(b[3])
An uncompressed block does not start with metadata.
An uncompressed block starts with a record header:
[4 bytes: record length, little-endian, bit 31 = "has headers"]
[8 bytes: sequence]
[8 bytes: timestamp]
[2 bytes: subject length]
...
A record length of exactly 7,368,035 bytes is 0x706D63.
In little-endian order, these bytes are 63 6D 70.
These bytes are the ASCII text "cmp".
This is the same as the compression magic prefix.
When the message has headers, bit 31 of the length field is set.
Then the fourth byte is 0x80.
UnmarshalMetadata reads this byte as the compression algorithm.
Algorithm 128 does not exist.
Decompress then returns "compression algorithm not known".
Each subsequent load of the block fails with the same error.
The block stays unreadable until retention deletes it.
Expected behavior
- The server reads each message that it stored, for all message sizes.
- The size of a message has no effect on the ability of the server to read it.
- If the server cannot read one message, the consumers continue with the next sequence.
Server and client version
nats-server v2.11.8
client: rust async-nats 0.45.0
Host environment
OS: Ubuntu 24.04.2 LTS, kernel 6.8.0-55-lowlatency, x86_64
Steps to reproduce
- Create a stream with file storage and no compression.
- Publish a message with headers. Make the total stored record length exactly 7,368,035 bytes (0x706D63). The record length is the sum of the 22-byte record header, the subject, the header block, the payload, and the checksum.
- Make sure the message is the first record of its block. A payload of this size starts a new block with the default block sizes.
- Remove the block from the cache. A server restart also does this.
- Try to read the message with
nats stream get <stream> <seq>.
- The read fails with "compression algorithm not known".
Note: other lengths also cause the collision. Each length with the low three bytes 63 6D 70 causes it. For blocks smaller than 16 MB, only 7,368,035 is possible.
Information for Stream STREAM_NAME created 2025-09-28 05:08:32
Subjects: stream.subject
Replicas: 1
Storage: File
Options:
Retention: Limits
Acknowledgments: true
Discard Policy: Old
Duplicate Window: 30m0s
Direct Get: true
Limits:
Maximum Messages: unlimited
Maximum Per Subject: unlimited
Maximum Bytes: 800 GiB
Maximum Age: 1d1h0m0s
Maximum Message Size: unlimited
Maximum Consumers: unlimited
Consumer state, captured while the consumer was stopped at the bad sequence (68,283,121):
Information for Consumer STREAM_NAME > CONSUMER_NAME created 2026-06-29 15:04:56
Configuration:
Name: CONSUMER_NAME
Pull Mode: true
Deliver Policy: From Sequence 61862235
Ack Policy: Explicit
Ack Wait: 30.00s
Replay Policy: Instant
Maximum Deliveries: 10
Max Ack Pending: 10,000
Max Waiting Pulls: 512
State:
Last Delivered Message: Consumer sequence: 6,452,554 Stream sequence: 68,283,120 Last delivery: 36m12s ago
Acknowledgment Floor: Consumer sequence: 6,452,554 Stream sequence: 68,283,120 Last Ack: 35m54s ago
Outstanding Acks: 0 out of maximum 10,000
Redelivered Messages: 1,885
Unprocessed Messages: 5,115
Waiting Pulls: 1 of maximum 512
Note: the consumer had active waiting pulls. The applications were healthy. The server did not deliver the next message. Four durable pull consumers on this stream showed the same state at the same sequence.
Observed behavior
[ERR] Received an error looking up message for consumer '$G > STREAM_NAME > CONSUMER_NAME': compression algorithm not knownnats stream getgives error 10037, "no message found".nats stream rmmgives error 10057, "compression algorithm not known".Root cause:
The filestore uses the first bytes of a block to find the compression metadata.
The function
CompressionInfo.UnmarshalMetadata(server/filestore.go) does this test(here in current main):
An uncompressed block does not start with metadata.
An uncompressed block starts with a record header:
A record length of exactly 7,368,035 bytes is 0x706D63.
In little-endian order, these bytes are
63 6D 70.These bytes are the ASCII text "cmp".
This is the same as the compression magic prefix.
When the message has headers, bit 31 of the length field is set.
Then the fourth byte is 0x80.
UnmarshalMetadatareads this byte as the compression algorithm.Algorithm 128 does not exist.
Decompressthen returns "compression algorithm not known".Each subsequent load of the block fails with the same error.
The block stays unreadable until retention deletes it.
Expected behavior
Server and client version
nats-server v2.11.8
client: rust async-nats 0.45.0
Host environment
OS: Ubuntu 24.04.2 LTS, kernel 6.8.0-55-lowlatency, x86_64
Steps to reproduce
nats stream get <stream> <seq>.Note: other lengths also cause the collision. Each length with the low three bytes
63 6D 70causes it. For blocks smaller than 16 MB, only 7,368,035 is possible.Information for Stream STREAM_NAME created 2025-09-28 05:08:32
Options:
Limits:
Consumer state, captured while the consumer was stopped at the bad sequence (68,283,121):
Note: the consumer had active waiting pulls. The applications were healthy. The server did not deliver the next message. Four durable pull consumers on this stream showed the same state at the same sequence.