Skip to content

DragonBattle#getEnderDragon throws internal NPE before End dimension is loaded for the first time #10970

@joshuaprince

Description

@joshuaprince

Only present in 1.21.

Stack trace

java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "key" is null
	at java.base/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936) ~[?:?]
	at ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup.get(EntityLookup.java:91) ~[main/:?]
	at ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup.get(EntityLookup.java:37) ~[main/:?]
	at net.minecraft.server.level.ServerLevel.getEntity(ServerLevel.java:1826) ~[main/:?]
	at org.bukkit.craftbukkit.boss.CraftDragonBattle.getEnderDragon(CraftDragonBattle.java:32) ~[main/:?]
	at test-plugin-1.0.0-SNAPSHOT.jar/io.papermc.testplugin.TestPlugin.onBreak(TestPlugin.java:32) ~[test-plugin-1.0.0-SNAPSHOT.jar:?]
	at com.destroystokyo.paper.event.executor.asm.generated.GeneratedEventExecutor1.execute(Unknown Source) ~[?:?]
	at org.bukkit.plugin.EventExecutor$2.execute(EventExecutor.java:77) ~[paper-api-1.21-R0.1-SNAPSHOT.jar:?]
	at co.aikar.timings.TimedEventExecutor.execute(TimedEventExecutor.java:81) ~[paper-api-1.21-R0.1-SNAPSHOT.jar:?]
	at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[paper-api-1.21-R0.1-SNAPSHOT.jar:?]
	at io.papermc.paper.plugin.manager.PaperEventManager.callEvent(PaperEventManager.java:54) ~[main/:?]
	at io.papermc.paper.plugin.manager.PaperPluginManagerImpl.callEvent(PaperPluginManagerImpl.java:131) ~[main/:?]
	at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:628) ~[paper-api-1.21-R0.1-SNAPSHOT.jar:?]
	at net.minecraft.server.level.ServerPlayerGameMode.destroyBlock(ServerPlayerGameMode.java:383) ~[main/:?]
	at net.minecraft.server.level.ServerPlayerGameMode.destroyAndAck(ServerPlayerGameMode.java:342) ~[main/:?]
	at net.minecraft.server.level.ServerPlayerGameMode.handleBlockBreakAction(ServerPlayerGameMode.java:215) ~[main/:?]
	at net.minecraft.server.network.ServerGamePacketListenerImpl.handlePlayerAction(ServerGamePacketListenerImpl.java:1785) ~[main/:?]
	at net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.handle(ServerboundPlayerActionPacket.java:51) ~[filteredMinecraft.jar:?]
	at net.minecraft.network.protocol.game.ServerboundPlayerActionPacket.handle(ServerboundPlayerActionPacket.java:20) ~[filteredMinecraft.jar:?]
	at net.minecraft.network.protocol.PacketUtils.lambda$ensureRunningOnSameThread$0(PacketUtils.java:36) ~[main/:?]
	at net.minecraft.server.TickTask.run(TickTask.java:18) ~[filteredMinecraft.jar:?]
	at net.minecraft.util.thread.BlockableEventLoop.doRunTask(BlockableEventLoop.java:151) ~[main/:?]
	at net.minecraft.util.thread.ReentrantBlockableEventLoop.doRunTask(ReentrantBlockableEventLoop.java:24) ~[filteredMinecraft.jar:?]
	at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:1478) ~[main/:?]
	at net.minecraft.server.MinecraftServer.doRunTask(MinecraftServer.java:201) ~[main/:?]
	at net.minecraft.util.thread.BlockableEventLoop.pollTask(BlockableEventLoop.java:125) ~[main/:?]
	at net.minecraft.server.MinecraftServer.pollTaskInternal(MinecraftServer.java:1456) ~[main/:?]
	at net.minecraft.server.MinecraftServer.pollTask(MinecraftServer.java:1449) ~[main/:?]
	at net.minecraft.util.thread.BlockableEventLoop.managedBlock(BlockableEventLoop.java:135) ~[main/:?]
	at net.minecraft.server.MinecraftServer.managedBlock(MinecraftServer.java:1408) ~[main/:?]
	at net.minecraft.server.MinecraftServer.waitUntilNextTick(MinecraftServer.java:1415) ~[main/:?]
	at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1260) ~[main/:?]
	at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:329) ~[main/:?]
	at java.base/java.lang.Thread.run(Thread.java:1583) ~[?:?]

Plugin and Datapack List

No plugins or datapacks, just the Paper TestPlugin with added logic to call DragonBattle#getEnderDragon (NB: this contains proper null checks)

    @EventHandler
    public void onBreak(BlockBreakEvent event) {
        World end = Bukkit.getWorlds().get(2);
        event.getPlayer().sendMessage(end.getName());

        DragonBattle battle = end.getEnderDragonBattle();
        event.getPlayer().sendMessage(battle == null ? "battle = null!" : battle.toString());
        if (battle == null) return;

        EnderDragon dragon = battle.getEnderDragon();  // <--- TestPlugin.java:32 mentioned in the stacktrace
        event.getPlayer().sendMessage(dragon == null ? "dragon = null!" : dragon.toString());
    }

Actions to reproduce (if known)

  1. Add the listener above to a test plugin
  2. Delete world_the_end and start the server
  3. Break a block (or otherwise trigger the code to run, BlockBreakEvent is just a hook to try this out)

Behavior in 1.20.6: No NPE, the line "dragon = null!" gets printed to the player.
Behavior in 1.21: NPE.

Paper version

This server is running Paper version 1.21-DEV (2024-06-24T00:56:05Z) (Implementing API version 1.21-R0.1-SNAPSHOT)
You are running a development version without access to version information

Git SHA: dd31654 (Paper 1.21 build 36)

Other

Caught this while testing a plugin with new worlds for 1.21. The stacktrace suggests it could affect other Entity lookups, but I couldn't get any others to trigger it.

The DragonBattle object is non-null in this situation on both 1.20.6 and 1.21. 1.20.6 properly returns EnderDragon as null, 1.21 throws this exception instead.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions