You dispose of the keycallback twice. Once in InputHandler.dispose() and then afterwards let LWJGL dispose of it again in HelloWorld.run() -> glfwFreeCallbacks, because LWJGL (or rather GLFW) does not know of your first disposal, since you did not clear/unregister the callback back in InputHandler.dispose().