From 43194250371db02ca4562a39580e95b7307cb49b Mon Sep 17 00:00:00 2001 From: KernelPanic Date: Thu, 13 Aug 2026 00:34:26 -0400 Subject: [PATCH] Fix network stream desync: write() used raw writeBytes(), read() expects writeByteArray()'s framing RegistryFriendlyByteBuf.write(serializer, data) wrote the encoded CBOR payload with plain writeBytes() - Netty's raw byte-array write, no length prefix. Its counterpart read(serializer) reads it back with readByteArray() - Minecraft's own length-prefixed format (a VarInt count followed by that many bytes). The two were never compatible; write() just had no real caller previously exercising the mismatch. That changed when streamCodec's implementation was refactored earlier this session to route through write()/read() instead of calling Nbt's/Cbor's encode/decode directly with matching writeByteArray/ readByteArray calls (as it used to). Any StreamCodec built via KSerializer.streamCodec now hit this immediately in CI: io.netty.handler.codec.DecoderException: ByteArray with size 12607 is bigger than allowed 703 readByteArray() misread the front of the raw CBOR bytes as if they were a VarInt length prefix, producing a garbage size - a real stream desync, not a flake. Reproduced locally via ComposeItemContainerMenuClientTests. testExcludedSlotBehaviorViaRealMenuOpen (uses a real menu-open network round trip), which was failing in CI (fabric:client, neoforge:client) on 1.21.x. Fix: write() now uses writeByteArray() to match read()'s framing. Verified: the previously-failing test now passes standalone, and the full :archie-gametest-neoforge:runGametestClient suite is clean (25/25 on a second run; the first run's single failure was the already-documented pre-existing "stale render state" flake, unrelated to this change). Co-Authored-By: Claude Sonnet 5 --- .../kotlin/net/kernelpanicsoft/archie/serialization/Utils.kt | 2 +- .../main/kotlin/net/kernelpanicsoft/archie/test/TestScreen.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/common/src/main/kotlin/net/kernelpanicsoft/archie/serialization/Utils.kt b/core/common/src/main/kotlin/net/kernelpanicsoft/archie/serialization/Utils.kt index f9ec2e292..d58f9974b 100644 --- a/core/common/src/main/kotlin/net/kernelpanicsoft/archie/serialization/Utils.kt +++ b/core/common/src/main/kotlin/net/kernelpanicsoft/archie/serialization/Utils.kt @@ -42,7 +42,7 @@ inline fun RegistryFriendlyByteBuf.write(data: T) = write(Seri * Writes data into a [RegistryFriendlyByteBuf] using a [KSerializer] */ fun RegistryFriendlyByteBuf.write(serializer: KSerializer, data: T) = - writeBytes(SerializationManager.cbor.encodeToByteArray(serializer, data)) + writeByteArray(SerializationManager.cbor.encodeToByteArray(serializer, data)) /** * Converts a [Codec] into a [KSerializer]. diff --git a/test/common/src/main/kotlin/net/kernelpanicsoft/archie/test/TestScreen.kt b/test/common/src/main/kotlin/net/kernelpanicsoft/archie/test/TestScreen.kt index 48d4bd8eb..6cc6ca78f 100644 --- a/test/common/src/main/kotlin/net/kernelpanicsoft/archie/test/TestScreen.kt +++ b/test/common/src/main/kotlin/net/kernelpanicsoft/archie/test/TestScreen.kt @@ -63,7 +63,7 @@ class TestScreen(menu: TestMenu, playerInventory: Inventory, title: Component) : val layerManager = LocalLayerManager.current var syncedValue by observeProperty("test", "") val test = syncedValue ?: "" - Theme(type = "bedrock", mode = "dark") { + Theme { Box(modifier = Modifier.width(contentWidth + 16)) { TabContainerPanel(contentWidth) { for (showcase in TestKind.entries) {