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
- Start a Fabric server on Minecraft 26.2 with only fabric-api, fabric-language-kotlin and Ledger installed
- Join and run:
/give @s minecraft:stone_pickaxe[minecraft:item_name={"translate":"item.minecraft.diamond"}]
- Open the inventory and click that item repeatedly
- 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
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.
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
/give @s minecraft:stone_pickaxe[minecraft:item_name={"translate":"item.minecraft.diamond"}]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
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.
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:
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.