{"record":{"id":"e72b8336365d9bfc","repo":"apache/maven","slug":"aggregator-mojo-is-already-being-executed-in-th","errorCode":null,"errorMessage":"{} aggregator mojo is already being executed in this parallel build, those kind of mojos require exclusive access to reactor to prevent race conditions. This mojo execution will be blocked until the aggregator mojo is done.","messagePattern":"(.+?) aggregator mojo is already being executed in this parallel build, those kind of mojos require exclusive access to reactor to prevent race conditions\\. This mojo execution will be blocked until the aggregator mojo is done\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java","lineNumber":249,"sourceCode":"     */\n    protected class ProjectLock implements NoExceptionCloseable {\n        final Lock acquiredAggregatorLock;\n        final OwnerReentrantLock acquiredProjectLock;\n\n        ProjectLock(MavenSession session, MojoDescriptor mojoDescriptor) {\n            mojos.put(Thread.currentThread(), mojoDescriptor);\n            boolean aggregator = mojoDescriptor.isAggregator();\n            acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock();\n            acquiredProjectLock = getProjectLock(session);\n            if (!acquiredAggregatorLock.tryLock()) {\n                Thread owner = aggregatorLock.getOwner();\n                MojoDescriptor ownerMojo = owner != null ? mojos.get(owner) : null;\n                String str = ownerMojo != null ? \" The \" + ownerMojo.getId() : \"An\";\n                String msg = str + \" aggregator mojo is already being executed \"\n                        + \"in this parallel build, those kind of mojos require exclusive access to \"\n                        + \"reactor to prevent race conditions. This mojo execution will be blocked \"\n                        + \"until the aggregator mojo is done.\";\n                warn(msg);\n                acquiredAggregatorLock.lock();\n            }\n            if (!acquiredProjectLock.tryLock()) {\n                Thread owner = acquiredProjectLock.getOwner();\n                MojoDescriptor ownerMojo = owner != null ? mojos.get(owner) : null;\n                String str = ownerMojo != null ? \" The \" + ownerMojo.getId() : \"A\";\n                String msg = str + \" mojo is already being executed \"\n                        + \"on the project \" + session.getCurrentProject().getGroupId()\n                        + \":\" + session.getCurrentProject().getArtifactId() + \". \"\n                        + \"This mojo execution will be blocked \"\n                        + \"until the mojo is done.\";\n                warn(msg);\n                acquiredProjectLock.lock();\n            }\n        }\n\n        @Override\n        public void close() {","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java#L231-L267","documentation":"MojoExecutor guards parallel builds with a read/write lock pair: aggregator mojos take the write lock (exclusive reactor access), all other mojos take a read lock. When a mojo's tryLock() fails because an aggregator mojo currently holds the write lock, Maven logs this warning and blocks the calling thread on aggregatorLock.lock() until the aggregator finishes. It is advisory only — correctness is preserved by the blocking; the message explains the temporary stall in 'mvn -T' builds.","triggerScenarios":"Running with -T/--threads while an aggregator mojo (@Aggregator or requiresProject=false, e.g. 'mvn -T 1C clean install javadoc:aggregate-jar', spotbugs:spotbugs, license:check on the root) is executing; enough other module mojos run concurrently that one of them reaches execute() while the aggregator holds the write lock.","commonSituations":"CI builds adding -T 1C or -T 4 for speed; aggregator/reporting goals (javadoc:aggregate, license:check, tidy) mixed into the same parallel reactor run; flaky ordering — the warning appears only when lock contention actually happens, so builds intermittently print it.","solutions":["Treat it as informational: the build is correct, that mojo just waits; if build time is acceptable, no action is needed.","Run aggregator goals in a separate sequential invocation (e.g. 'mvn -T 1C package' then 'mvn javadoc:aggregate-jar') to remove the stall.","Reduce thread count (-T 2) or run the whole build without -T if contention dominates wall-clock time.","Replace the aggregator goal with a per-module goal plus an aggregation step in a later phase, so it need not lock the whole reactor."],"exampleFix":"# before: aggregator goal contends with parallel module builds\nmvn -T 1C clean install javadoc:aggregate-jar\n\n# after: split into a parallel build and a sequential aggregation step\nmvn -T 1C clean install\nmvn javadoc:aggregate-jar","handlingStrategy":"validation","validationCode":"# guard: detect aggregator goals before enabling -T\nmvn help:describe -Dplugin=org.apache.maven.plugins:maven-javadoc-plugin -Ddetail \\\n  | grep -i aggregat\n# if aggregator goals are in the plan, split the run instead of mixing with -T","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run aggregator goals (javadoc:aggregate, license:check on root) as separate sequential invocations after the parallel build.","Remember the warning is benign: the lock guarantees mutual exclusion; treat it as a wall-clock signal, not an error.","Budget -T thread counts so one aggregator does not serialize the tail of the build."],"tags":["maven","parallel-build","aggregator","lock-contention","concurrency"],"backgroundTag":"parallel-build-lock-contention","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}