Rejected Allay interaction leaves client inventory and equipment visually desynchronized
Nobody has claimed this yet.
- Dominant language
- Shell
- Stars
- 4.4k
- Forks
- 623
- PR merge metrics
- No merged PRs in 30d
Description
Expected behavior
If an entity-interaction packet cannot be processed, Folia should immediately restore the authoritative player inventory and target equipment state.
The held item should either be transferred exactly once or remain visible in the player's hand. The client should not show a temporary loss or an apparent duplicate.
Observed/Actual behavior
When two Allays are leashed together and moving, right-clicking an Allay with a single item can occasionally leave the client-predicted state in place:
- the held stack disappears client-side;
- both Allays may appear to hold the same item;
- opening/closing the inventory (or another full sync) restores the original item.
Authoritative server-side inventory snapshots retained exactly one dirt item throughout the reproduction window, so this was not a realized item duplication. The failed interaction also did not reach PlayerInteractEntityEvent.
Steps/models to reproduce
- Start a Folia server and spawn two Allays.
- Leash the two Allays to each other with a single lead.
- Move them so they are actively being pulled. The observed occurrences happened while the entities could be undergoing tick-region ownership handoff.
- Hold exactly one ordinary item (dirt was used in the recording).
- Right-click the moving Allays to give them the item.
- Repeat while they move. Intermittently the client shows the item removed from the hand and both Allays holding it.
- Open and close the player inventory. The original item returns because the authoritative server state never consumed it.
Recordings:
The reproduction is intermittent; I do not yet have deterministic region coordinates.
Plugin and Datapack List
No custom datapacks.
Plugins:
- all custom plugins. not 3rd party.
Folia version
This server is running Folia version 26.1.2-8-ver/26.1.x@62dc0f2 (2026-05-06T13:45:28Z) (Implementing API version 26.1.2.build.8-stable)
You are running the latest version
Other
This appears to be a rejected client-predicted interaction that is not reconciled, rather than an actual item dupe.
In ServerGamePacketListenerImpl.handleInteract, target interaction processing is guarded by conditions including:
target != null && TickThread.isTickThreadFor(target) && ...
If that guard is false, the packet is silently ignored. No Bukkit interaction event is fired and no corrective player inventory or target equipment packet is sent. By contrast, the later Bukkit-event cancellation path already calls containerMenu.sendAllDataToRemote() and explicitly resends equipment for an Allay.
The leading explanation is that the linked/moving Allay changes tick-region ownership between packet dispatch and handling. Historical logs cannot prove which guard failed, so range or world-border rejection could produce the same visible result. Regardless of the exact rejected guard, the packet handler leaves a client-predicted mutation unreconciled.
The relevant ownership guard was introduced in 5b5f8dc.
A safe fix would keep the ownership check, but reconcile every rejected predicted interaction by resending the player's authoritative inventory/container state. If target equipment also needs correction, that sync should be scheduled on the target entity's owning region rather than processing the interaction off-region.
Important limitation: this was observed on a plugin server and has not yet been reproduced on a clean Folia instance. The packet-related custom plugins were audited: they only observe/forward ordinary entity-interaction packets in this path, and none intentionally modifies the player's inventory or an Allay for this interaction.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in ServerGamePacketListenerImpl.handleInteract and inspect the ownership guard introduced by commit 5b5f8dc. Reproduce the moving, leashed Allay interaction on Folia and compare rejected-packet handling with the later Bukkit-event cancellation path, which resends inventory and Allay equipment. Done means rejected client-predicted interactions reconcile authoritative state without processing off-region.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100