{"record":{"id":"8e6e2324fca4a02c","repo":"apache/maven","slug":"mojo-is-already-being-executed-on-the-project","errorCode":null,"errorMessage":"{} mojo is already being executed on the project {}:{} This mojo execution will be blocked until the mojo is done.","messagePattern":"(.+?) mojo is already being executed on the project (.+?):(.+?) This mojo execution will be blocked until the 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":261,"sourceCode":"                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() {\n            // release the lock in the reverse order of the acquisition\n            acquiredProjectLock.unlock();\n            acquiredAggregatorLock.unlock();\n            mojos.remove(Thread.currentThread());\n        }\n\n        private OwnerReentrantLock getProjectLock(MavenSession session) {\n            SessionData data = session.getSession().getData();\n            Map<MavenProject, OwnerReentrantLock> locks = data.computeIfAbsent(PROJECT_LOCKS, ConcurrentHashMap::new);\n            return locks.computeIfAbsent(session.getCurrentProject(), p -> new OwnerReentrantLock());\n        }\n    }","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java#L243-L279","documentation":"The same MojoExecutor lock scheme also serializes access per project: getProjectLock(session) returns a per-project lock, and when tryLock() fails because another thread is already running a mojo on the same G:A, this warning is logged and the thread blocks until that mojo completes. It indicates two mojos were scheduled concurrently for one module — usually an aggregator-adjacent overlap or forked executions targeting the same project.","triggerScenarios":"Parallel build (-T) where two mojo executions for the same project overlap in the schedule — e.g. a direct goal plus a lifecycle phase for the same module, forked executions (compiler:compile with <fork>) re-entering the same project, or an aggregator finishing while a module mojo starts on that project.","commonSituations":"Mixing direct goal invocations with lifecycle phases for the same module under -T; plugins that fork other lifecycles on the same project; large CI reactors with -T 1C where the scheduler overlaps a module's mojos.","solutions":["Accept the warning: execution is serialized correctly, the second mojo just waits; verify wall-clock impact before changing anything.","Invoke the module's goals in one lifecycle run (e.g. 'mvn -T 1C install') instead of adding direct goals that race the lifecycle for the same module.","Lower the thread count or drop -T for the affected module set if stalls are measurable.","For plugin authors: avoid forking executions that re-target the same project during parallel builds."],"exampleFix":"# before: direct goal and lifecycle overlap on the same module under -T\nmvn -T 4 myplugin:rebuild-module install\n\n# after: single lifecycle pass, no overlapping executions per project\nmvn -T 4 install","handlingStrategy":"validation","validationCode":"# guard: one lifecycle pass per module; avoid direct goals racing the same project under -T\n# instead of: mvn -T 4 direct-goal install\nmvn -T 4 install","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not combine direct goal invocations and lifecycle phases for the same module in one -T run.","Review plugins that fork executions on the same project; they serialize on the project lock.","Accept the stall message as informational; per-project serialization is required for correctness."],"tags":["maven","parallel-build","project-lock","concurrency","lifecycle"],"backgroundTag":"parallel-build-lock-contention","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}