[Crash]: ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 256
pietro-lopes opened this issue ยท 7 comments
Steps to Reproduce the Crash
Join a multiplayer world
Exit the world
Try to a singleplayer world
You will get an error that prevents you from joining
javaw_BC30OsPI2X.mp4
Mod Pack URL (Optional)
No response
Mod Pack Version (Optional)
No response
Extra Notes (Optional)
This was tested with only JEI on the instance.
I did a little debugging and the recipe serializer jei:jei_shaped is somewhat related to it
Crash Report
It is the interaction between RegistryManager/RegistrySnapshot.
Set a breakpoint at:
net.minecraft.core.MappedRegistry#clear
with condition this.toString().contains("recipe")
net.minecraft.core.MappedRegistry#registerIdMapping
with condition key.toString().contains("jei_shaped")
net.neoforged.neoforge.registries.RegistrySnapshot#RegistrySnapshot(net.minecraft.core.Registry, boolean) (this is the constructor)
with condition registry.toString().contains("recipe_serializer")
--
Loading game, taking a vanilla snapshot: Ids and registry all fine
Still loading game, now a frozen snapshot: Still ids and registry fine
Going to load a Multiplayer world
Apply snapshot is called and will clear partially the registry (only byId and toId)
Logged in, now I will disconnect
Now I will join my Singleplayer world
Some snapshot will be taken and notice the size of the maps does not match
when registry.getId(key) runs and get a key that is not mapped, it will give -1
Now snapshot is poisoned with a -1 Id
Some more clearing
It will now try add to the mapping that cursed -1 that it got from the snapshot
Setting -1 here causes the ArrayIndexOutOfBoundsException
Hello,
Sorry JEI does not sync anything at startup in 1.21.1, so I am not sure how it can be the cause of this particular issue.
The JEI shaped recipes only exist on the client and aren't added to the vanilla registry.
Can you share your findings about jei:jei_shaped?
Fun fact: when you lose connection/is disconnected on that multiplayer, looks like a revertToFrozen is called and makes joining singleplayer normally.
Did this as a test and it fixes this issue
(calling this on client side only)
public class FixSnapshot {
private static final VarHandle DISCONNECTION_HANDLED;
static {
DISCONNECTION_HANDLED = ReflectionHelper.getFieldFromClass(Connection.class, "disconnectionHandled", boolean.class, false);
}
public FixSnapshot() {
var gamebus = NeoForge.EVENT_BUS;
gamebus.addListener(this::callRevertToFrozenOnDisconnect);
}
private void callRevertToFrozenOnDisconnect(ClientPlayerNetworkEvent.LoggingOut event) {
if (Minecraft.getInstance().getConnection() instanceof ClientPacketListener listener) {
var handled = (boolean)DISCONNECTION_HANDLED.get(listener.getConnection());
if (!listener.getConnection().isMemoryConnection() && !handled) {
RegistryManager.revertToFrozen();
}
}
}
}Tested and it does not call twice or in on wrong moment like login
Works for single player (will skip), multiplayer clicking quit (will trigger), or multiplayer being disconnected (will skip)
Thanks for the analysis @pietro-lopes , it's rare that someone is so motivated to help dig in!
I wasn't aware of this functionality/optimization in the NeoForge registry manager when I registered my serializers to it. After looking at it for a bit, I think there is a potential that this is a NeoForge bug.
The NeoForge devs have a much deeper understanding of this, so for now the most efficient route to fixing it is to follow @ChampionAsh5357 's new NeoForge issue:
If the issue is in JEI after all, I'll be happy to accept their guidance to fix it!
Will be fixed by neoforged/NeoForge#1944















