Skip to content

Fix IndexOutOfBoundsException in AlternativeCommandsHandler.getAlternative - #6609

Open
minoneer wants to merge 1 commit into
EssentialsX:2.xfrom
minoneer:2.x
Open

Fix IndexOutOfBoundsException in AlternativeCommandsHandler.getAlternative#6609
minoneer wants to merge 1 commit into
EssentialsX:2.xfrom
minoneer:2.x

Conversation

@minoneer

Copy link
Copy Markdown

Information

This PR fixes #6608.

Details

Proposed fix:

getAlternative prunes collected WeakReferences through its own iterator, which can remove
every entry in a bucket. The following commands.get(0) then throws IndexOutOfBoundsException.

This stores the first live alias during the iteration and returns that instead, or null when
nothing live remains, which is what the caller already tests for
(getAlternative(label) == null in EssentialsPlayerListener.CommandSendFilter).

Confirmed with an instrumented build that logged the list sizes around the prune loop:

[6608] label=w thread=Paper Async Command Builder Thread Pool - 0
       entry=2 removedByUs=2 after=0 expected=0

Both references in the w bucket had been collected and the loop removed both.

Note: this does not address the possible concurrent modification also raised in #6608
(altCommands is a plain HashMap of ArrayList, modified from the async command-send path).
That needs a separate synchronisation decision.

Environments tested:

OS: Debian 12

Java version: 25.0.4 2026-07-21 LTS

  • Most recent Paper version (26.2, git-Paper-112)
  • CraftBukkit/Spigot/Paper 1.12.2
  • CraftBukkit 1.8.8

Demonstration:

Before, on every boot with a player join (5 consecutive boots, EssentialsX 2.22.0 and
2.22.1-dev+17-382de4f, same server and plugin set):

[ERROR]: Could not pass event AsyncPlayerSendCommandsEvent to Essentials
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
    at java.util.ArrayList.get(ArrayList.java:428)
    at com.earth2me.essentials.AlternativeCommandsHandler.getAlternative(AlternativeCommandsHandler.java:133)
    at com.earth2me.essentials.EssentialsPlayerListener$CommandSendFilter.isEssentialsCommand(EssentialsPlayerListener.java:1279)
    at net.ess3.provider.providers.PaperCommandSendListenerProvider.onAsyncCommandSend(PaperCommandSendListenerProvider.java:28)
...

Cause isolated with a temporary instrumented build logging list sizes around the prune loop:

[6608] label=w thread=Paper Async Command Builder Thread Pool - 0
       entry=2 removedByUs=2 after=0 expected=0

Both WeakReference in the w bucket had been collected and the loop removed both.

After, with this fix (2.22.1-dev+18), same server, player join:

IndexOutOfBoundsException:                0
AlternativeCommandsHandler references:    0
Could not pass event AsyncPlayerSendCommandsEvent: 0

…ative

getAlternative prunes collected WeakReferences through its own iterator, which
can remove every entry in a bucket. The following commands.get(0) then throws
IndexOutOfBoundsException.

Store the first live alias during the iteration and return that instead, or null
when nothing live remains - which the caller already treats as "no alternative".

Fixes EssentialsX#6608
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IndexOutOfBoundsException on player join

1 participant