theonedev/onedev · error · IllegalArgumentException
Path '${treePath}' does not exist or is not a tree.
Error message
Path '${treePath}' does not exist or is not a tree. What it means
LastCommitsOfChildren computes the last commit that touched each child of a directory in a git tree. Before walking, it resolves the given treePath against the 'until' commit's tree with TreeWalk.forPath; if the path does not exist, or exists but is a blob (file) rather than a directory, it throws this IllegalArgumentException. Only an existing directory (FileMode.TREE) can have children.
Source
Thrown at server-core/src/main/java/org/eclipse/jgit/revwalk/LastCommitsOfChildren.java:91
@Nullable String treePath, @Nullable final Cache cache) {
try (RevWalk revWalk = new RevWalk(repo)) {
treePath = GitUtils.normalizePath(treePath);
if (treePath == null)
treePath = "";
final byte[] treePathRaw = Constants.encode(treePath);
final Set<String> children = new HashSet<>();
final Set<String> modifiedChildren = new HashSet<>();
RevCommit untilCommit = revWalk.parseCommit(until);
/*
* Find out child directory or file names under the tree
*/
if (treePath.length() != 0) {
TreeWalk treeWalk = TreeWalk.forPath(repo, treePath, untilCommit.getTree());
if (treeWalk == null || !FileMode.TREE.equals(treeWalk.getFileMode(0)))
throw new IllegalArgumentException("Path '" + treePath + "' does not exist or is not a tree.");
treeWalk.enterSubtree();
treeWalk.setRecursive(false);
while (treeWalk.next())
children.add(treeWalk.getPathString().substring(treePath.length()+1));
} else {
try (TreeWalk treeWalk = new TreeWalk(repo)) {
treeWalk.addTree(untilCommit.getTree());
treeWalk.setRecursive(false);
while (treeWalk.next())
children.add(treeWalk.getPathString().substring(treePath.length()));
}
}
revWalk.markStart(untilCommit);
revWalk.setRewriteParents(false);
/*
* Records last commits info of first encountered commit in cache, and we View on GitHub (pinned to d44925c47c)
Solutions
- Verify the path exists and is a directory in the same commit passed as untilCommit before constructing LastCommitsOfChildren (TreeWalk.forPath(repo, path, untilCommit.getTree()) != null and FileMode.TREE.equals(tw.getFileMode(0))).
- Normalize the path: strip leading/trailing '/' and resolve '.'/'..' segments.
- If the path is a file, request last-commit data for the file's parent directory instead, or use a file-oriented API.
- Handle the case where the directory was deleted in untilCommit by falling back to the commit where it last existed.
- Catch IllegalArgumentException as a signal to return 404/not-a-directory to the caller.
Example fix
// before
LastCommitsOfChildren children = new LastCommitsOfChildren(project.getRepository(), commit, path);
// after
try (RevWalk rw = new RevWalk(project.getRepository())) {
RevCommit c = rw.parseCommit(commit.getId());
if (!path.isEmpty()) {
TreeWalk tw = TreeWalk.forPath(project.getRepository(), path, c.getTree());
if (tw == null || !FileMode.TREE.equals(tw.getFileMode(0)))
throw new NotFoundException("Path is not a directory in commit " + c.getName());
}
}
LastCommitsOfChildren children = new LastCommitsOfChildren(project.getRepository(), commit, path); Defensive patterns
Strategy: validation
Validate before calling
boolean isDirectoryIn(Repository repo, RevCommit c, String path) throws IOException {
if (path == null || path.isEmpty()) return true;
String p = StringUtils.strip(path, "/");
try (TreeWalk tw = TreeWalk.forPath(repo, p, c.getTree())) {
return tw != null && FileMode.TREE.equals(tw.getFileMode(0));
}
} Type guard
boolean isTreeMode(TreeWalk tw) { return tw != null && FileMode.TREE.equals(tw.getFileMode(0)); } Try / catch
try {
return new LastCommitsOfChildren(repo, commit, path);
} catch (IllegalArgumentException e) {
throw new ResourceNotFoundException("Directory not found in commit: " + path);
} Prevention
- Resolve the path against the same commit you pass as untilCommit
- Strip leading/trailing slashes and normalize '..' before use
- Distinguish file vs directory paths in your UI/URL routing
- Cache paths together with the commit id they were valid for
When it happens
Trigger: Calling new LastCommitsOfChildren(repo, untilCommit, path) where path is empty-but-null-adjacent misspellings aside: (1) the path does not exist in the commit's tree (deleted/renamed/typo), (2) the path is a file, not a directory, (3) the path exists only in another branch/commit than untilCommit, (4) leading/trailing slashes or non-normalized paths that JGit cannot resolve.
Common situations: Rendering a file-browser 'last modified per entry' view in OneDev where a user-supplied path param points to a file or a stale path after a refactor; caching a directory path from an older commit and reusing it against a newer untilCommit where the directory was removed; building the path by string concatenation producing double slashes.
Related errors
- Path '" + blobIdent.path + "' is a tree"
- Can only compare with common ancestor when different project
- Ref name is required when commit hash is specified
- Either commit hash, branch or tag should be specified
- Unable to find commit to import build spec (import project:
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/3cca0bee3c53ec0e.
Report an issue: GitHub.