Callback API can quickly lead to memory leaks
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 12.7k
- Forks
- 3.5k
- Avg merge
- 3d 13h
- Merged PRs (30d)
- 11
Description
Description
The Paper callback API can quickly lead to memory leaks. I've only looked at DialogAction.customClick with the callback parameter, which registers a new callback, but it looks like this applies to all callbacks using this system.
Context
Using the above mentioned method appears to be the most easy way to get a response from a dialog click, but doing so leads to a callback being registered, which can quickly lead to a memory leak as those callbacks (by default) are valid for 12 hours and won't automatically be invalidated if the dialog gets closed or the player quits.
Example
@EventHandler(ignoreCancelled = true)
public void onInteract(PlayerInteractEntityEvent event) {
if (event.getHand() != EquipmentSlot.HAND) return;
Player player = event.getPlayer();
player.showDialog(Dialog.create(builder -> {
builder.empty()
.base(DialogBase.builder(Component.text("Are you sure, you want to interact with this entity?")).build())
.type(DialogType.confirmation(
ActionButton.builder(Component.text("Yes, sir!"))
.action(DialogAction.customClick((response, audience) -> {
player.setVelocity(new Vector(0, 5, 0));
}, ClickCallback.Options.builder().build()))
.build(),
ActionButton.builder(Component.text("Nope!"))
.action(DialogAction.customClick((response, audience) -> {
audience.sendMessage(Component.text("ok."));
}, ClickCallback.Options.builder().build()))
.build()
));
}));
}
This example demonstrates the issues I see with the current state of the callback system: 2 callbacks are registered when showing the dialog.
- Those callbacks are registered for 12 hours, after clicking one button the other callbacks remains registered, although the dialog gets closed.
- There is no way to invalidate a callback once registered (I may be wrong here, but I was not able to see any option, feel free to correct me if there is one)
- Even when using a single action dialog the callback won't be invalidated if the player disconnects or gets another dialog opened.
This also prevents objects (like in this case the player) from getting garbage collected. Yes: this should be avoided, but it's easy to accidentally have e.g. a player reference end up in this callback, which quickly results in a memory leak.
Improvements
- Add a way to invalidate a callback (e.g. to be able to invalidate callbacks onQuit or when a dialog gets closed). Maybe this is already possible, but I am unable to find the method?
- Specific to the dialog action callback: Maybe bind it to a player or dialog and automatically invalidate it once the dialog is closed or the player disconnected.
- Add a warning to the Dialog API docs that using callbacks can lead to memory leaks, when the callback holds references to big objects.
This example may be a "worst case" example, but it demonstrates how quickly you can cause a memory leak and in this case with the dialog action you can't really avoid it (yes you can avoid using the player reference, but you can't avoid the leak of callback instances because you can't invalidate them). The only option to avoid this is not using the customClick method which registers the callback and instead use the event based click detection approach.
Please let me know if there is a way to invalidate a callback manually as this would solve most of my issues.
Paper version
Tested on
1.21.10-87-main@b5b7c79 (2025-10-25T19:06:05Z) (Implementing API version 1.21.10-R0.1-SNAPSHOT)
You are running the latest version
Previous version: 1.21.10-82-1e67ca8 (MC: 1.21.10)
as well as the latest 1.21.8 build
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at DialogAction.customClick and trace the callback registration and lifetime handling described in the issue. Review the Dialog API callbacks documentation linked in the report. Done should include a clear invalidation or lifecycle behavior for callbacks, coverage for dialog closure and player disconnect cases, and documentation of any remaining retention risks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend-api-design, documentation
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100