Skip to content

fix: encode null as varint(-1) in VarIntBytes for correct Kafka tombstones#217

Merged
ShogunPanda merged 4 commits intoplatformatic:mainfrom
tburch:fix/tombstone-null-encoding
Feb 20, 2026
Merged

fix: encode null as varint(-1) in VarIntBytes for correct Kafka tombstones#217
ShogunPanda merged 4 commits intoplatformatic:mainfrom
tburch:fix/tombstone-null-encoding

Conversation

@tburch
Copy link
Copy Markdown
Contributor

@tburch tburch commented Feb 10, 2026

Summary

Fixes #216

Writer.appendVarIntBytes() encodes null values as varint(0) (empty byte array) instead of varint(-1) (null) per the Kafka protocol specification. Reader.readVarIntBytes() has the symmetric bug — it converts -1 back to an empty buffer, masking the issue when both sides use @platformatic/kafka.

This breaks tombstone semantics for any non-@platformatic/kafka consumer:

  • Log compaction — empty byte arrays are retained instead of signaling key deletion
  • Kafka ConnectAvroConverter throws BufferUnderflowException on 0-byte values
  • Any consumer expecting null — sees empty bytes instead of null

Changes

src/protocol/writer.tsappendVarIntBytes(null) now writes varint(-1) instead of varint(0)

src/protocol/reader.tsreadVarIntBytes() now returns null when it reads varint(-1), instead of converting to empty buffer. Return type updated to Buffer | null.

Tests updated to match corrected behavior.

@ShogunPanda
Copy link
Copy Markdown
Contributor

Can you please sign the DCO?

@ShogunPanda
Copy link
Copy Markdown
Contributor

Also, can you please fix CI?

@tburch
Copy link
Copy Markdown
Contributor Author

tburch commented Feb 11, 2026

Sorry @ShogunPanda! Fixed the CI and signed the DCO.

@tburch tburch force-pushed the fix/tombstone-null-encoding branch from e58118e to 0c740da Compare February 11, 2026 17:55
…tones

Writer.appendVarIntBytes() was encoding null values as varint(0) (empty
byte array) instead of varint(-1) (null) per the Kafka protocol spec.
Reader.readVarIntBytes() had the symmetric bug, converting -1 back to
empty buffer, masking the issue in pure @platformatic/kafka environments.

This broke tombstone semantics for any non-@platformatic/kafka consumer:
- Log compaction retains empty byte arrays instead of deleting keys
- Kafka Connect AvroConverter throws BufferUnderflowException on 0-byte values
- Any consumer expecting null for key deletion sees empty bytes instead

Fixes platformatic#216

Signed-off-by: Tristan Burch <tristan@day.ai>
The protocol layer now correctly reads/writes null values, but the
KafkaRecord TypeScript types still declared Buffer-only. This updates
the types to Buffer | null and adds null coalescing in the consumer
deserializer calls so null values from tombstone records are safely
handled.

Signed-off-by: Tristan Burch <tristan@day.ai>
@tburch tburch force-pushed the fix/tombstone-null-encoding branch from 0c740da to a70cd28 Compare February 11, 2026 17:56
@ShogunPanda
Copy link
Copy Markdown
Contributor

ShogunPanda commented Feb 12, 2026

@tburch I'm afraid you missed one entry. Once you fix it I'll approve and merge.

…ltering

The KafkaRecord key type is `Buffer | null`, but `#filterUncommittedMessages`
accessed `batch.records[0].key.readInt16BE(2)` without a null check, causing
TS2531. Use optional chaining to handle the case where key is null.

Signed-off-by: Tristan Burch <tristan@day.ai>
@tburch
Copy link
Copy Markdown
Contributor Author

tburch commented Feb 18, 2026

@ShogunPanda pushed a fix that I think will take care of it.

Copy link
Copy Markdown
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina mcollina requested a review from ShogunPanda February 19, 2026 08:45
@ShogunPanda
Copy link
Copy Markdown
Contributor

@tburch Unfortunately it is still failing.
Can you try again. Also run against npm run lint and npm run typecheck before pushing.

readVarIntBytes() now returns Buffer | null, so all test and playground
code that accesses record key/value/headers needs null-aware handling.

Signed-off-by: Tristan Burch <tristan@day.ai>
@tburch tburch requested a review from mcollina February 19, 2026 16:42
@ShogunPanda ShogunPanda merged commit 2836b73 into platformatic:main Feb 20, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Writer.appendVarIntBytes() writes varint(0) for null values instead of varint(-1), breaking Kafka tombstones

3 participants