Hi,

The statement that "the unsolicited install happens [...] to make the resume `-r` feature work" is only partially true. The original solution to get `mvn -r` to work did /not/ involve installing all artifacts in a project-local repo. It was later refactored/rewritten by /other/ people to work the way you describe.

Thanks,

Maarten

On August 4, 2026 at 15:07, Tamás Cservenák wrote:
Howdy,

I would just reflect on a funny fact (for me at least):

This whole problem (being solved on this thread), stems from one
single thing: the unsolicited install that Maven 4 does (cf this to
user invoking `mvn install` explicitly).

Moreover, this unsolicited install happens, for one thing, to make the
resume `-r` feature work.

And the true irony is, that this resume feature is backed and
advertised by folks, whose mantra is "do not `mvn install` but `mvn
verify`" (as install "pollutes' your local repository", whatever that
means).

That mantra can be now extended with "... as Maven 4 will install it,
even if you did not ask for it" :)

The more I think about it, the more I find this funny.

Thanks
T

On Tue, 4 Aug 2026 at 14:56, Guillaume Nodet<[email protected]> wrote:
I like the .mvn/target/project-local-repo which solves the problem,
and also provides a good location where plugins could move some
temporary data files without being disturbed by the clean plugin.  I'm
thinking about the flatten plugin, the release plugin, and probably
more.

Le lun. 3 août 2026 à 16:47, Slawomir Jaranowski
<[email protected]> a écrit :
Hi,

On Mon, 3 Aug 2026 at 14:09, Guillaume Nodet<[email protected]> wrote:
Hi all,

I'd like to get your input on the fix for GH-12646 — a race condition with
project-local-repo during parallel clean install builds.

The problem

When the root pom.xml has a parent that is also part of the reactor (e.g. a
super-pom), MultiThreadedBuilder schedules the parent first, then runs the
root project and child modules concurrently. Since clean and install are
placed into the same TaskSegment, there is no barrier between them — the
root project's maven-clean-plugin can delete target/ while sibling modules
are concurrently writing artifacts into target/project-local-repo, causing
the build to fail.

Approaches considered

1. Lock-based synchronization (ReentrantReadWriteLock in ReactorReader)

Acquire a write lock when the project owning target/ enters its clean
phase, and a read lock when installing artifacts. This prevents the crash
(concurrent access) but does not guarantee ordering — a module could
install artifacts before the root's clean starts, only to have them wiped.
It also adds complexity to ReactorReader for what is fundamentally an
architectural problem.

2. Move project-local-repo to ~/.m2/ (user home)

E.g. ~/.m2/local-repository/${projectName}_${hash}, similar to how IntelliJ
stores project caches. This avoids both the race and the git concern, but:
- Hard links (already used by ReactorReader) cannot cross filesystem
boundaries — if ~/.m2/ is on a different volume, every artifact becomes a
full copy
- Stale directories accumulate when projects are deleted/moved, with no
cleanup mechanism
- CI containers often share ~/.m2/ across builds, causing unwanted
accumulation
- Loses project locality (harder to inspect/debug)

3. Move project-local-repo to .mvn/project-local-repo (chosen)

Move the directory from target/project-local-repo to
.mvn/project-local-repo. Since maven-clean-plugin only deletes target/, the
race becomes structurally impossible. ReactorReader fully owns the
lifecycle — per-GAV cleanup when a project enters its clean phase, install
on project success. The existing hard-link optimization continues to work
since both directories are on the same filesystem.

The trade-off is that .mvn/project-local-repo needs to be gitignored. This
follows the Gradle convention where .gradle/ at the project root is
universally in .gitignore templates. Maven could also document this
convention or consider auto-appending the entry.

The fix itself is minimal — the core change is a single line in
getProjectLocalRepo(), and the rest is removing the lock infrastructure
(net -40 lines).

4. Keep in target/ but use maven-clean-plugin fast mode

The fast clean option (maven.clean.fast=true, since plugin 3.2) atomically
renames target/ instead of recursively deleting it. This would likely avoid
the race, but it's opt-in and not the default — users hitting the bug would
need to know about it.

FWIW, a PR has been raised on m-clean-p master branch (4.x) to refactor the
fast cleaner (fixing problems) and make it the default.

Open questions

- Is .mvn/ the right location, or should we consider a different
project-root directory?
maybe .mvn/target/project-local-repo
it should be ignored by git

- Should Maven auto-add .mvn/project-local-repo to .gitignore, or document
it as a convention?
- Are there other considerations I'm missing?

PR:https://github.com/apache/maven/pull/12650
Issue:https://github.com/apache/maven/issues/12646

Looking forward to your thoughts.

  Cheers
Guillaume Nodet


--
Sławomir Jaranowski

---------------------------------------------------------------------
To unsubscribe, e-mail:[email protected]
For additional commands, e-mail:[email protected]


--
------------------------
Guillaume Nodet

---------------------------------------------------------------------
To unsubscribe, e-mail:[email protected]
For additional commands, e-mail:[email protected]

---------------------------------------------------------------------
To unsubscribe, e-mail:[email protected]
For additional commands, e-mail:[email protected]

Reply via email to