quarkusio/quarkus · error · java.lang.IllegalArgumentException
Expected a path relative to the root of the path tree but go
Error message
Expected a path relative to the root of the path tree but got
What it means
PathTreeVisit.ensureResourcePath() rejects resource paths that are absolute, since lookups must be relative to the path tree root. It throws IllegalArgumentException 'Expected a path relative to the root of the path tree but got <path>' when the string is a Unix absolute path (leading '/') or a Windows absolute path (drive letter or UNC), or starts with the default separator.
Source
Thrown at independent-projects/bootstrap/app-model/src/main/java/io/quarkus/paths/PathTreeVisit.java:38
private static volatile Pattern windowsAbsolutePathPattern;
private static Pattern windowsAbsolutePathPattern() {
return windowsAbsolutePathPattern == null ? windowsAbsolutePathPattern = Pattern.compile("[a-zA-Z]:\\\\.*")
: windowsAbsolutePathPattern;
}
static boolean isAbsolutePath(String path) {
return path != null && !path.isEmpty()
&& (path.charAt(0) == '/' // we want to check for '/' on every OS
|| USE_WINDOWS_ABSOLUTE_PATH_PATTERN
&& (windowsAbsolutePathPattern().matcher(path).matches())
|| path.startsWith(FileSystems.getDefault().getSeparator()));
}
static void ensureResourcePath(FileSystem fs, String path) {
if (isAbsolutePath(path)) {
throw new IllegalArgumentException("Expected a path relative to the root of the path tree but got " + path);
}
// this is to disallow reading outside the path tree root
if (path != null && path.contains("..")) {
for (Path pathElement : fs.getPath(path)) {
if (pathElement.toString().equals("..")) {
throw new IllegalArgumentException("'..' cannot be used in resource paths, but got " + path);
}
}
}
}
static String resourceNameToFsPath(String resourceName, FileSystem fs) {
return fs.getSeparator().equals("/") ? resourceName : resourceName.replace("/", fs.getSeparator());
}
static void walk(Path root, Path rootDir, Path walkDir, PathFilter pathFilter, Map<String, String> multiReleaseMapping,
PathVisitor visitor) {
final PathTreeVisit visit = new PathTreeVisit(root, rootDir, pathFilter, multiReleaseMapping);View on GitHub (pinned to e1c734241f)
Solutions
- Strip the leading root/separator before lookup: convert absolute paths to relative via rootPath.relativize(p).toString().
- Normalize manually: remove a leading '/' (or drive prefix) with something like path.startsWith("/") ? path.substring(1) : path.
- Never pass values from getAbsolutePath()/Path.toString() of absolute paths into resource lookups; keep resource names as symbolic relative strings.
- Catch IllegalArgumentException and log the offending path to quickly identify the producer of absolute paths.
Example fix
// before
Path resource = tree.getPath("/config/app.properties"); // IllegalArgumentException
// after
String rel = "/config/app.properties";
if (rel.startsWith("/")) {
rel = rel.substring(1);
}
Path resource = tree.getPath(rel); Defensive patterns
Strategy: validation
Validate before calling
static String toRelativeResourcePath(String path) {
if (path.startsWith("/") || path.startsWith("\\") || (path.length() > 1 && path.charAt(1) == ':')) {
throw new IllegalArgumentException("Resource path must be relative: " + path);
}
return path;
} Type guard
static boolean isRelativeResourcePath(String path) {
if (path == null || path.isEmpty()) return false;
if (path.startsWith("/") || path.startsWith("\\")) return false;
if (path.length() > 1 && path.charAt(1) == ':') return false; // Windows drive
return true;
} Try / catch
try {
tree.apply(visit, resourcePath);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Expected a path relative")) {
String rel = resourcePath.replaceFirst("^/", "");
tree.apply(visit, rel);
} else {
throw e;
}
} Prevention
- Never pass File.getAbsolutePath()/absolute Path.toString() results into resource lookups.
- Keep resource names as constant relative strings ("config/app.properties").
- Strip leading separators when a path may come from user config.
- Also avoid '..' segments — ensureResourcePath rejects them separately.
When it happens
Trigger: Calling lookup/apply/walk APIs (e.g. PathTree.apply or PathTreeWalk) with a path string like '/foo/bar.txt' or 'C:\\data\\x.txt'; concatenating a root path with a resource name and passing the result; copying code that used File.getAbsolutePath().
Common situations: Mistakenly passing absolute paths obtained from config or from Path.toString() of an absolute file; Windows-specific absolute paths surfacing on path joins; porting code from java.io.File to resource lookup.
Related errors
- does not exist
- does not exist
- Name cannot start with '/':${name}
- Predicate already set
- Location already set
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/9e8660b67d69e408.
Report an issue: GitHub.