Skip to content

Items with translatable text components cause intermittent cursor desync (phantom item on cursor) #387

Description

@HappyHackingOrange

Update: this is upstream in Server Translations API, which Ledger bundles — see NucleoidMC/Server-Translations#74. Details in the comment below.

Expected behavior

Clicking an item in an inventory picks it up cleanly and the cursor shows exactly one item, as it does when Ledger is not installed.

Observed/actual behavior

Clicking an inventory item that carries a translatable text component leaves a phantom copy of that item attached to the cursor. The item is not actually held: clicking any other slot clears it, and the server's inventory state stays correct. Nothing is thrown and nothing appears in the log.

It happens on roughly 4 clicks in 10, so it is a race rather than a deterministic failure. Removing Ledger eliminates it entirely, and it never occurs in single-player.

Steps/models to reproduce

  1. Start a Fabric server on Minecraft 26.2 with only fabric-api, fabric-language-kotlin and Ledger installed
  2. Join and run: /give @s minecraft:stone_pickaxe[minecraft:item_name={"translate":"item.minecraft.diamond"}]
  3. Open the inventory and click that item repeatedly
  4. Around 4 clicks in 10 leave a phantom pickaxe stuck to the cursor. Clicking any other slot clears it.

No datapack or resource pack is required; a vanilla translation key is enough. Substituting a literal item_name, {"text":"Test"}, never reproduces it.

What operating system are you running

Linux

Minecraft version

26.2

Ledger version

1.3.23

Logs

https://mclo.gs/R83evu3

Agreements

  • I am running the latest version of the mod.
  • My version of Minecraft is supported.
  • I have searched for and ensured there isn't already an open issue regarding this.

Other

Two logs from the same server, back to back, which is where the isolation comes from:

Nothing else changed between the two boots. Neither log contains an exception; the bug is silent.

Components Text kind Ghosts
none - 0/10
item_model - 0/10
lore literal 0/10
item_name literal 0/10
lore translatable 2/10
item_name translatable 4/10
item_name + lore + item_model includes translatable 7/10
all 9 components from a real modded item includes translatable 4/10

Literal text never triggers it; translatable content triggers it in either component. Adding six further non-text components on top (last row) does not raise the rate, so this is not payload size - it is specific to translation resolution.

Possible cause, unverified: Ledger bundles server_translations_api, which intercepts translatable components to localise them per player. If that resolution runs on the inventory-transaction path it would widen the window between the client's optimistic pickup and the server's confirmation, which fits both the symptom and its intermittency. I have not read the source, so please treat this as a starting point rather than a diagnosis.

Ruled out:

  • All client mods, bisected, including the inventory mods Mouse Wheelie and Tweakeroo
  • Shaders (Iris) and every resource pack
  • All other server mods - reproduced with fabric-api + Kotlin + Ledger only
  • Datapacks, including one that writes to player inventories on an inventory_changed advancement
  • Single-player: does not reproduce
  • Item provenance: a /give replica ghosts at the same rate as a crafted original, and /data get shows identical components

Attempted workaround that does not help: setting typeBlacklist = ["item-insert", "item-remove", "item-drop", "item-pickup"] in config/ledger.toml. The blacklist filters the database write, not the hook.

Impact is cosmetic - no duplication, no item loss, server state stays correct. It is persistent though, and affects any server whose items have translatable names, which is most modded or datapack servers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions