Skip to content

fix: NBT serialization crash in ArchieFluidSlot/Storage and ArchieEnergyStorage - #9

Merged
KP2048 merged 1 commit into
1.21.xfrom
worktree-fix-fluid-slot-serialization
Aug 7, 2026
Merged

fix: NBT serialization crash in ArchieFluidSlot/Storage and ArchieEnergyStorage#9
KP2048 merged 1 commit into
1.21.xfrom
worktree-fix-fluid-slot-serialization

Conversation

@KP2048

@KP2048 KP2048 commented Aug 7, 2026

Copy link
Copy Markdown
Member

Summary

Found by running ./gradlew check locally (asked to look at the latest run of :check; the GitHub-hosted run was still in progress, so ran it locally instead). It crashed:

net.benwoodworth.knbt.internal.NbtEncodingException:
Cannot encode TAG_Compound within a TAG_List of TAG_Long

ArchieFluidSlot.Serializer and ArchieFluidStorage.Serializer both declared a multi-field, class-shaped SerialDescriptor but implemented serialize()/deserialize() as flat, unwrapped sequential encoder/decoder calls instead of encoder.encodeStructure/decoder.decodeStructure. Harmless for a single slot in isolation, but breaks the moment a slot holding real (non-blank) content sits inside ArchieFluidStorage's list: knbt commits to a homogeneous list-element shape from the first raw encodeLong call, then chokes when that same slot's serialize() call goes on to write a compound-shaped resourceStack. Any real mod filling an NBTHolder.fluidField(...) tank and triggering a save would hit this — it wasn't specific to the new test, just nothing had exercised that path with a non-empty fluid before.

Fixed both to properly wrap encode/decode in encodeStructure/decodeStructure. Found the identical pattern in ArchieEnergyStorage's serializer too — not currently triggered (energyField is never list-nested), but the same latent defect, fixed for consistency while in the area.

Also investigated a separate client-GameTest flakiness found during this same :check run (not caused by this fix — confirmed via 5x repeated local runs and comparison against unrelated pre-existing CI failures). Root-caused it as far as static analysis allows and documented findings in AGENTS.md rather than guessing at a fix; a real fix (bringing the harness's coroutine scope in line with how real Jetpack Compose's own test tooling avoids this class of race) is scoped as a separate follow-up PR.

Test plan

  • The specific test that originally crashed (BlockEntityNBTHolderTests.testItemFluidAndEnergyFieldsPersistMutations) now passes
  • Full local fabric:runGametest server-side suite: green
  • :common:compileKotlin clean

🤖 Generated with Claude Code

…gyStorage

Found by running ./gradlew check locally (the user asked to look at the
latest run - GitHub's runner was mid-flight, so this ran it locally
instead), which crashed on the new test added in the docs-sync work:

    net.benwoodworth.knbt.internal.NbtEncodingException:
    Cannot encode TAG_Compound within a TAG_List of TAG_Long

ArchieFluidSlot.Serializer and ArchieFluidStorage.Serializer both declared a
multi-field class-shaped SerialDescriptor but implemented serialize()/
deserialize() as flat, unwrapped sequential encoder/decoder calls instead of
encoder.encodeStructure/decoder.decodeStructure. Harmless for a single slot
in isolation, but breaks the moment a slot holding real (non-blank) content
sits inside ArchieFluidStorage's list: knbt commits to a homogeneous list
element shape from the first raw encodeLong call, then chokes when the same
slot's serialize() call goes on to write a compound-shaped resourceStack.
Any real mod filling an NBTHolder.fluidField(...) tank and triggering a save
would hit this - it wasn't specific to the test, just nothing had exercised
that path with a non-empty fluid before.

Fixed both to properly wrap their encode/decode in encodeStructure/
decodeStructure. Found the identical pattern (descriptor says structured,
implementation writes flat) in ArchieEnergyStorage's serializer too - not
currently triggered (energyField is never list-nested), but the same latent
defect, so fixed for consistency while in the area.

Verified: the specific failing test now passes, and a full local
`fabric:runGametest` server-side suite run is green.

Also investigated a separate, pre-existing client-GameTest flakiness (not
caused by this fix - confirmed via 5x repeated local runs, 4 passed, and by
comparing against pre-existing CI failures on unrelated PRs). Documented
what was found and ruled out in AGENTS.md rather than guessing at a fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@KP2048
KP2048 marked this pull request as ready for review August 7, 2026 02:11
Copilot AI lite review requested due to automatic review settings August 7, 2026 02:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@KP2048
KP2048 merged commit b71f22b into 1.21.x Aug 7, 2026
7 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.

2 participants