Skip to content

[Bug] compile_and_reload_modified_files always throws "reloadChangedClasses API is not available" — void HotSwapUI method's null return misjudged as unavailable (5.2.0) #310

Description

@lkaiiu

Summarycompile_and_reload_modified_files (MCP tool) always fails with:

java.lang.IllegalStateException: Java Debugger HotSwap reloadChangedClasses API is not available

even though the hot reload actually takes effect (new code runs in the attached JVM). Reproduced on IDEA 2026.2 (build 262.9437.185) + DebugTools plugin 5.2.0, both for apps launched via DebugTools Hotswap executor and via other launchers.

Root cause (decompiled evidence from plugin jar 5.2.0)

The implementation is in (not present in this GitHub repo, see note below):
io.github.future0923.debug.tools.idea.mcp.tools.compileandreloadmodifiedfiles.CompileAndReloadModifiedFilesMcpService.reloadChangedClasses(Project, Object, boolean)

Decompiled bytecode logic (simplified):

fun reloadChangedClasses(project, session, compileBeforeReload) {
    val hotSwapUI = HotSwapUI.getInstance(project)
    val target = hotSwapUI.getClass().getMethods().firstOrNull {
        it.name == "reloadChangedClasses" && it.parameterCount == 2
        && it.parameterTypes[0].isInstance(session)
        && it.parameterTypes[1] == Boolean.TYPE
    }
    if (target != null) {
        val result = target.invoke(hotSwapUI, session, compileBeforeReload)
        if (result == null) {                       // ← BUG: always true
            throw IllegalStateException("Java Debugger HotSwap reloadChangedClasses API is not available")
        }
    } else {
        throw IllegalStateException("...")
    }
}

The bug: com.intellij.debugger.ui.HotSwapUI#reloadChangedClasses is a void method (verified with javap against IDEA 2026.2 intellij.java.debugger.impl.jar):

public abstract void reloadChangedClasses(com.intellij.debugger.impl.DebuggerSession, boolean);
public abstract void reloadChangedClasses(com.intellij.debugger.impl.DebuggerSession, boolean, com.intellij.debugger.ui.HotSwapStatusListener);

Method.invoke() on a void method always returns null, so the result == null check is always true → the tool always reports "API is not available", even though the reload was already submitted successfully (which is why the new code still takes effect).

Suggested fix

Do not check the return value of a void method. Either call it directly (no reflection), or drop the null check and only treat an exception (e.g. InvocationTargetException wrapping a real error) as failure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions