Skip to content

IDE hook crashes Maven 4 #2584

@SapiensAnatis

Description

@SapiensAnatis

I am looking at developing a VSCode plugin for Spotless that works with Maven. For performance reasons I want to use mvnd which is a daemon-based version of Maven, and which is based on Maven 4.x.

I have found that on Maven 4, if I invoke:

$ mvn spotless:apply -DspotlessIdeHook=/home/jay/Projects/vscode-spotless-maven/test-project/src/main/java/com/mycompany/app/App.java

then it executes successfully but crashes Maven while cleaning up:

[INFO] Scanning for projects...
[INFO] 
[INFO] -----------------------------------------------< com.mycompany.app:my-app >-----------------------------------------------
[INFO] Building my-app 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] ---------------------------------------------------------[ jar ]----------------------------------------------------------
[INFO] 
[INFO] --- spotless:2.46.1:apply (default-cli) @ my-app ---
[WARNING] [stderr] IS CLEAN
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] --------------------------------------------------------------------------------------------------------------------------
[INFO] Total time:  0.802 s
[INFO] Finished at: 2025-08-02T16:33:13+01:00
[INFO] --------------------------------------------------------------------------------------------------------------------------
[ERROR] Unable to close context
org.apache.maven.api.cli.InvokerException: Unable to close context
        at org.apache.maven.cling.invoker.LookupContext.close(LookupContext.java:128)
        at org.apache.maven.cling.invoker.LookupInvoker.invoke(LookupInvoker.java:143)
        at org.apache.maven.cling.ClingSupport.run(ClingSupport.java:76)
        at org.apache.maven.cling.MavenCling.main(MavenCling.java:51)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
        at java.base/java.lang.reflect.Method.invoke(Method.java:565)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:255)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:201)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:361)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:314)
        Suppressed: java.lang.NullPointerException: Cannot invoke "org.apache.maven.logging.LoggingOutputStream.forceFlush()" because "this.out" is null
                at org.apache.maven.logging.LoggingOutputStream$LoggingPrintStream.forceFlush(LoggingOutputStream.java:88)
                at org.apache.maven.logging.LoggingOutputStream.forceFlush(LoggingOutputStream.java:94)
                at org.apache.maven.cling.invoker.LookupInvoker.lambda$doConfigureWithTerminalWithRawStreamsDisabled$3(LookupInvoker.java:378)
                at org.apache.maven.cling.invoker.LookupContext.close(LookupContext.java:118)
                ... 9 more
        Suppressed: java.lang.NullPointerException: Cannot invoke "org.apache.maven.logging.LoggingOutputStream.forceFlush()" because "this.out" is null
                at org.apache.maven.logging.LoggingOutputStream$LoggingPrintStream.forceFlush(LoggingOutputStream.java:88)
                at org.apache.maven.logging.LoggingOutputStream.forceFlush(LoggingOutputStream.java:94)
                at org.apache.maven.cling.invoker.LookupInvoker.lambda$doConfigureWithTerminalWithRawStreamsDisabled$1(LookupInvoker.java:376)
                at org.apache.maven.cling.invoker.LookupContext.close(LookupContext.java:118)
                ... 9 more

Note that Spotless doesn't crash Maven if you don't use the IDE hook.

I have been able to narrow this down to the following code in the Maven IDE hook:

} finally {
System.err.close();
System.out.close();
}

I believe this code is the cause because if I make my own minimal mojo on Maven 4.x which looks like this:

package sample.plugin;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;

@Mojo(name = "sayhi")
public class GreetingMojo extends AbstractMojo
{
    @Override
    public void execute() throws MojoExecutionException
    {
        getLog().info("Hello, world.");

        System.err.close();
        System.out.close();
    }
}

then I am able to reproduce the same crash with mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi. If I then comment those two lines of code out, the crash disappears.

I wanted to ask why we need to close stdout/stderr after the IDE hook has finished? It might well be that this is a Maven issue rather than a Spotless issue (it doesn't feel like a plugin should be able to crash the host build system) but if we can do a quick fix here rather than waiting for a change in Maven that would be great.

Issue template

spotless version: 2.46.1
maven version: Apache Maven 4.0.0-rc-4 (bed0f8174bf728978f86fac533aa38a9511f3872)
repro: https://github.com/SapiensAnatis/vscode-spotless-maven/tree/master/test-project (but any Spotless project will work fine if my understanding of the cause is correct)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions