You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "gnodet (via GitHub)" <gi...@apache.org> on 2026/09/23 22:14:03 UTC
[PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
gnodet opened a new pull request, #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344
## Summary
Fix `mvn clean` crash with `NoSuchFileException` in Windows Docker environments when `followSymlinks=true`.
## Root Cause
When `followSymlinks=true`, `Cleaner.delete(Path)` calls `getCanonicalPath(basedir, null)` which internally
calls `path.toRealPath()`. On Windows Docker environments, volume-mount reparse points cause `toRealPath()`
to throw `NoSuchFileException` due to [JDK-8172711](https://bugs.openjdk.org/browse/JDK-8172711).
This only affects users who explicitly configure `<followSymLinks>true</followSymLinks>` — the default is
`false`, so the vast majority of users are unaffected.
See: https://github.com/apache/maven-clean-plugin/issues/262#issuecomment-5803635630
## Fix
Wrap the `getCanonicalPath(basedir, null)` call in a `try/catch (IOException e)`. On failure, log a debug
message and continue with the original (unresolved) `basedir`.
`FOLLOW_LINKS` is still added to the `walkFileTree` options before the try/catch, so symlink following via
`Files.walkFileTree` still works normally. The only loss on a `toRealPath()` failure is the loop-detection
benefit of canonicalization — which is benign in practice (Docker volume mounts don't form symlink loops).
Note: `BackgroundCleaner` already uses `toAbsolutePath()` instead of `toRealPath()` for a related reason
(the staging directory may not exist yet) — this fix brings the same robustness to the foreground cleaner.
## Tests
Added `deleteWithFollowSymlinksDeletesTarget` in `CleanerTest` to verify that `followSymlinks=true` correctly
deletes through a symlink when `toRealPath()` succeeds (the normal case). The error path (when `toRealPath()`
throws on Windows Docker reparse points) cannot be reproduced in standard CI and is documented in the test
comment instead.
All 16 tests pass (`./mvn verify -B`).
## Fixes
Fixes #262
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
Posted by "desruisseaux (via GitHub)" <gi...@apache.org>.
desruisseaux commented on code in PR #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344#discussion_r4092175791
##########
src/main/java/org/apache/maven/plugins/clean/Cleaner.java:
##########
@@ -282,7 +282,18 @@ public final void delete(@Nonnull Path basedir) throws IOException {
var options = EnumSet.noneOf(FileVisitOption.class);
if (followSymlinks) {
options.add(FileVisitOption.FOLLOW_LINKS);
- basedir = getCanonicalPath(basedir, null);
+ try {
+ basedir = getCanonicalPath(basedir, null);
+ } catch (IOException e) {
+ /*
+ * Fall back to the original (unresolved) path. This can happen on Windows Docker volumes
+ * where volume-mount reparse points cause toRealPath() to throw NoSuchFileException
+ * (JDK-8172711). FOLLOW_LINKS is still set above so symlink following still works via
+ * walkFileTree; the only loss is the loop-detection benefit of canonicalization, which
+ * is benign in practice.
+ */
+ logger.debug("Could not resolve real path of \"" + basedir + "\", continuing with original path: " + e);
Review Comment:
Indeed.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344#discussion_r4093377210
##########
src/test/java/org/apache/maven/plugins/clean/CleanerTest.java:
##########
@@ -134,4 +135,23 @@ void deleteDoesNotLogAnythingWhenNoPermissionAndWarnDisabled(@TempDir Path tempD
assertDoesNotThrow(() -> cleaner.delete(basedir));
verify(log, never()).warn(any(CharSequence.class), any(Throwable.class));
}
+
+ /**
+ * Verifies that {@code followSymlinks=true} deletes the directory correctly when {@code toRealPath()}
+ * succeeds (normal case). The fallback code path (when {@code toRealPath()} throws, as on Windows Docker
+ * volume reparse points due to JDK-8172711) cannot be reproduced in standard CI and is therefore not
+ * covered by an automated test.
+ */
+ @Test
+ @DisabledOnOs(OS.WINDOWS)
+ void deleteWithFollowSymlinksDeletesTarget(@TempDir Path tempDir) throws Exception {
+ final Path target = createDirectory(tempDir.resolve("target")).toRealPath();
+ createFile(target.resolve("file"));
+ final Path link = createSymbolicLink(tempDir.resolve("link"), target);
+ // followSymlinks=true triggers the getCanonicalPath() call (and the new try/catch)
+ final var cleaner = new Cleaner(matcherFactory, log, false, true, false, true, false);
+ cleaner.delete(link);
+ assertFalse(exists(target));
+ verify(log, never()).debug(any(CharSequence.class));
Review Comment:
⚠️ **Incomplete assertion — the new 2-arg debug call isn't covered.**
The assertion verifies `debug(CharSequence)` (one-arg) is never called. But the fallback code you added calls `logger.debug(msg, e)` — the **two-arg** `debug(CharSequence, Throwable)` overload. Mockito treats these as distinct method signatures, so this `verify` won't catch an accidental invocation of the fallback in this (normal) test path.
Add the two-arg check to make the assertion exhaustive:
```suggestion
verify(log, never()).debug(any(CharSequence.class));
verify(log, never()).debug(any(CharSequence.class), any(Throwable.class));
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet merged PR #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344#discussion_r4087887260
##########
src/main/java/org/apache/maven/plugins/clean/Cleaner.java:
##########
@@ -282,7 +282,18 @@ public final void delete(@Nonnull Path basedir) throws IOException {
var options = EnumSet.noneOf(FileVisitOption.class);
if (followSymlinks) {
options.add(FileVisitOption.FOLLOW_LINKS);
- basedir = getCanonicalPath(basedir, null);
+ try {
+ basedir = getCanonicalPath(basedir, null);
+ } catch (IOException e) {
+ /*
+ * Fall back to the original (unresolved) path. This can happen on Windows Docker volumes
+ * where volume-mount reparse points cause toRealPath() to throw NoSuchFileException
+ * (JDK-8172711). FOLLOW_LINKS is still set above so symlink following still works via
+ * walkFileTree; the only loss is the loop-detection benefit of canonicalization, which
+ * is benign in practice.
+ */
+ logger.debug("Could not resolve real path of \"" + basedir + "\", continuing with original path: " + e);
Review Comment:
⚠️ **Stack trace lost on the error path.**
`logger.debug("..." + e)` calls `e.toString()` and embeds it as a plain string, discarding the stack trace. When this actually fires on a Windows Docker host — which is exactly the scenario you're trying to diagnose — the stack trace is the most useful piece of information for understanding *which* system call failed and why. Use the two-argument overload instead:
```suggestion
logger.debug("Could not resolve real path of \"" + basedir + "\", continuing with original path", e);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] fix: fall back to original path when toRealPath() fails (fixes #262) [maven-clean-plugin]
Posted by "gnodet (via GitHub)" <gi...@apache.org>.
gnodet commented on code in PR #344:
URL: https://github.com/apache/maven-clean-plugin/pull/344#discussion_r4098657325
##########
src/test/java/org/apache/maven/plugins/clean/CleanerTest.java:
##########
@@ -134,4 +135,23 @@ void deleteDoesNotLogAnythingWhenNoPermissionAndWarnDisabled(@TempDir Path tempD
assertDoesNotThrow(() -> cleaner.delete(basedir));
verify(log, never()).warn(any(CharSequence.class), any(Throwable.class));
}
+
+ /**
+ * Verifies that {@code followSymlinks=true} deletes the directory correctly when {@code toRealPath()}
+ * succeeds (normal case). The fallback code path (when {@code toRealPath()} throws, as on Windows Docker
+ * volume reparse points due to JDK-8172711) cannot be reproduced in standard CI and is therefore not
+ * covered by an automated test.
+ */
+ @Test
+ @DisabledOnOs(OS.WINDOWS)
+ void deleteWithFollowSymlinksDeletesTarget(@TempDir Path tempDir) throws Exception {
+ final Path target = createDirectory(tempDir.resolve("target")).toRealPath();
+ createFile(target.resolve("file"));
+ final Path link = createSymbolicLink(tempDir.resolve("link"), target);
+ // followSymlinks=true triggers the getCanonicalPath() call (and the new try/catch)
+ final var cleaner = new Cleaner(matcherFactory, log, false, true, false, true, false);
+ cleaner.delete(link);
+ assertFalse(exists(target));
+ verify(log, never()).debug(any(CharSequence.class));
Review Comment:
Fixed in 4aadccf.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org