Skip to content

[Bug, 1.20.1] Crash on tooltip render when iterating a 3rd-party MEStorage (AE Omni Cells Universal Cell, fastutil ConcurrentModification-style NPE) #45

@PsyGuy007-sys

Description

@PsyGuy007-sys

Environment

  • Minecraft: 1.20.1
  • Loader: Forge 47.4.9
  • AppliedE: 0.14.3
  • ProjectE: 1.0.1
  • Applied Energistics 2: 15.4.10
  • AE Omni Cells: 1.1.1 (the addon whose cell ends up throwing)
  • ExtendedAE (provides GuiExDrive)

What happens

Player opens an ExtendedAE Drive GUI and hovers a slot. ProjectE's ToolTipEvent fires, AppliedE's InventoryItemProcessor.recalculateEMC walks the hovered cell's MEStorage, and the iteration crashes with an NPE coming out of fastutil internals.

Full crash log (mclo.gs raw): https://api.mclo.gs/1/raw/BsWtZbV

Exception

java.lang.NullPointerException: Cannot invoke "it.unimi.dsi.fastutil.objects.ObjectArrayList.get(int)" because "this.wrapped" is null
    at it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap$MapIterator.nextEntry(Object2LongOpenHashMap.java:705)
    at it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap$EntryIterator.next(Object2LongOpenHashMap.java:797)
    at com.wintercogs.ae2omnicells.common.me.AEUniversalCellInventory.getAvailableStacks(AEUniversalCellInventory.java:389)
    at appeng.api.storage.MEStorage.getAvailableStacks(MEStorage.java:110)
    at gripe._90.appliede.emc.InventoryItemProcessor.recalculateEMC(InventoryItemProcessor.java:54)
    at moze_intel.projecte.emc.nbt.NBTManager.getEmcValue(NBTManager.java:68)
    at moze_intel.projecte.utils.EMCHelper.getEmcValue(EMCHelper.java:151)
    at moze_intel.projecte.events.ToolTipEvent.tTipEvent(ToolTipEvent.java:52)

Why I'm filing this against AppliedE too

The immediate bug is on the AE Omni Cells side (their storage map isn't safe against concurrent iteration — I've filed an issue there: https://github.com/Frostbite-time/AE2OmniCells/issues — please link once available). The fastutil wrapped-null pattern is the textbook signature of "map mutated while an iterator was alive".

But InventoryItemProcessor.recalculateEMC is what triggered the iteration here, from the client render thread (ToolTipEvent). Walking a live MEStorage from the render thread is fragile by design — every cell-providing addon (Mega Cells, ExtraCells, AE Omni Cells, Functional Storage shims, etc.) is a candidate for the same crash class as soon as their storage is sync'd off-thread.

It would be worth considering, on AppliedE's side, one of:

  1. Snapshot the cell contents before iterating (copy KeyCounter/the underlying map under a try/catch, then process the snapshot).
  2. Wrap the getAvailableStacks call in a try/catch that logs once and returns "no EMC" for that tooltip — a busted addon shouldn't crash the client.
  3. Run EMC recalculation off the render thread and cache the result; tooltip just reads the cached value.

Option 2 alone would already turn this from "client crash" into "tooltip is missing EMC for a tick", which is a much more acceptable failure mode given the cross-mod surface area AppliedE has to deal with.

Repro

  1. MC 1.20.1 / Forge / ProjectE / AppliedE 0.14.3 / AE2 / AE Omni Cells 1.1.1 / ExtendedAE.
  2. Put any Universal Cell from AE Omni Cells into an ExtendedAE Drive on a network with content flowing.
  3. Open the drive GUI and hover the cell slot — instant crash (intermittent, more likely while the cell is being written to).

Workarounds for users hitting this

  • Don't hover slots in an ExtendedAE Drive containing Universal Cells, or
  • Temporarily disable AppliedE while removing the cell.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions