PaperMC / PaperMC/Paper

PluginEvents called out of order.

Open
#7,475 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: unlikely type: bug version: 1.18
Dominant language
Java
Stars
12.7k
Forks
3.5k
Avg merge
3d 13h
Merged PRs (30d)
11

Description

Expected behavior

I expect to see the events for PluginEnableEvent and PluginDisableEvent reflect the reality of the situation, in that the plugin failed during enablement.

Either the enable event should not be thrown if the event failed to initialize, or the events called in the correct order.

Observed/Actual behavior
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Loading Paper-Test-Plugin-watcher v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-stopper] Loading Paper-Test-Plugin-stopper v1.0.0-SNAPSHOT
[22:29:48 INFO]: Server permissions file permissions.yml is empty, ignoring it
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Enabling Paper-Test-Plugin-watcher v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-watcher::PluginEnableEvent
[22:29:48 INFO]: [Paper-Test-Plugin-stopper] Enabling Paper-Test-Plugin-stopper v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-stopper] Disabling Paper-Test-Plugin-stopper v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper::PluginDisableEvent
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper::PluginEnableEvent
[22:29:48 INFO]: Preparing level "world"
[22:29:49 INFO]: Preparing start region for dimension minecraft:overworld
[22:29:50 INFO]: Time elapsed: 586 ms
[22:29:50 INFO]: Preparing start region for dimension minecraft:the_nether
[22:29:50 INFO]: Time elapsed: 310 ms
[22:29:50 INFO]: Preparing start region for dimension minecraft:the_end
[22:29:51 INFO]: Time elapsed: 566 ms
[22:29:51 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-watcher = true
[22:29:51 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper = false

Note that enable and disable logging lines are in the correct order, but the event is not.

[22:29:48 INFO]: [Paper-Test-Plugin-stopper] Enabling Paper-Test-Plugin-stopper v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-stopper] Disabling Paper-Test-Plugin-stopper v1.0.0-SNAPSHOT
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper::PluginDisableEvent
[22:29:48 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper::PluginEnableEvent

Note that the status of the stopper is correctly disabled at server load time.

[22:29:51 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-watcher = true
[22:29:51 INFO]: [Paper-Test-Plugin-watcher] Paper-Test-Plugin-stopper = false
Steps/models to reproduce

Watcher: (Note: Stopper should probably depend on Watcher)

package io.papermc.paper.testplugin;

import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.event.server.PluginEvent;
import org.bukkit.event.server.ServerLoadEvent;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.Arrays;
import java.util.logging.Level;

public final class TestPluginWatcher extends JavaPlugin implements Listener {
    @Override
    public void onEnable() {
        this.getServer().getPluginManager().registerEvents(this, this);
    }


    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
    private void onPluginEnableEvent(final PluginEnableEvent e) {
        this.onPluginEvent(e);
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
    private void onPluginDisableEvent(final PluginDisableEvent e) {
        this.onPluginEvent(e);
    }

    private void onPluginEvent(final PluginEvent e) {
        this.getLogger().log(Level.INFO, e.getPlugin().getName()+"::"+e.getEventName());
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = false)
    private void onReady(ServerLoadEvent e) {
        Arrays.stream(this.getServer().getPluginManager().getPlugins())
            .map(p -> p.getName()+" = "+this.getServer().getPluginManager().isPluginEnabled(p))
            .forEach(s -> this.getLogger().log(Level.INFO, s));
    }
}

Stopper:

package io.papermc.paper.testplugin;

import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.Arrays;
import java.util.logging.Level;

public final class TestPluginStopper extends JavaPlugin implements Listener {
    @Override
    public void onEnable() {
        this.getServer().getPluginManager().disablePlugin(this);
    }

Plugin and Datapack List

Just the 2 listed above.

Paper version

Latest, at time of writing:

[22:37:31 INFO]: This server is running Paper version null (MC: 1.18.1) (Implementing API version 1.18.1-R0.1-SNAPSHOT) (Git: null on null)
Unknown version, custom build?
Other

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the ordering with the TestPluginWatcher and TestPluginStopper entry points, focusing on JavaPlugin.onEnable(), PluginManager.disablePlugin(), PluginEnableEvent, and PluginDisableEvent. Trace the plugin lifecycle and event dispatch to determine why disable is observed before enable, then verify that the emitted events match the logged plugin state and add regression coverage if the repository provides a suitable test location.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.