theonedev/onedev · error · ObjectAlreadyExistsException
Path already exist: " + treeWalk.getPathString()
Error message
Path already exist: " + treeWalk.getPathString()
What it means
During DefaultGitService tree insertion (used by commit/restore operations), when walking the old tree a path segment matches a new blob name that also exists as a directory conflict: if the existing entry at that position is a tree (TYPE_TREE) while a new blob of the same name is being added, it throws ObjectAlreadyExistsException("Path already exist: <path>") — a blob and a tree cannot occupy the same path.
Source
Thrown at server-core/src/main/java/io/onedev/server/git/service/DefaultGitService.java:704
Long projectId = project.getId();
ObjectId commitId = runOnProjectServer(projectId, new ClusterTask<>() {
private ObjectId insertTree(RevTree revTree, TreeWalk treeWalk, ObjectInserter inserter,
String parentPath, Set<String> currentOldPaths, Map<String, BlobContent> currentNewBlobs) {
try {
List<TreeFormatterEntry> entries = new ArrayList<>();
while (revTree != null && treeWalk.next()) {
String name = treeWalk.getNameString();
if (currentOldPaths.contains(name)) {
currentOldPaths.remove(name);
BlobContent currentNewBlob = currentNewBlobs.remove(name);
if (currentNewBlob != null) {
ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, currentNewBlob.getBytes());
entries.add(new TreeFormatterEntry(name, currentNewBlob.getMode(), blobId));
}
} else if (currentNewBlobs.containsKey(name)) {
if ((treeWalk.getRawMode(0) & FileMode.TYPE_MASK) == FileMode.TYPE_TREE) {
throw new ObjectAlreadyExistsException("Path already exist: " + treeWalk.getPathString());
} else {
BlobContent currentNewBlob = currentNewBlobs.remove(name);
ObjectId blobId = inserter.insert(Constants.OBJ_BLOB, currentNewBlob.getBytes());
entries.add(new TreeFormatterEntry(name, currentNewBlob.getMode(), blobId));
}
} else {
Set<String> childOldPaths = new HashSet<>();
for (Iterator<String> it = currentOldPaths.iterator(); it.hasNext(); ) {
String currentOldPath = it.next();
if (currentOldPath.startsWith(name + "/")) {
childOldPaths.add(currentOldPath.substring(name.length() + 1));
it.remove();
}
}
Map<String, BlobContent> childNewBlobs = new HashMap<>();
for (Iterator<Map.Entry<String, BlobContent>> it = currentNewBlobs.entrySet().iterator();
it.hasNext(); ) {
Map.Entry<String, BlobContent> entry = it.next();View on GitHub (pinned to d44925c47c)
Solutions
- Rename the new file so it does not collide with the existing directory path
- If replacing a directory with a file, perform two commits: first delete all files under the directory, then add the file
- Pre-validate in the caller that no new blob path prefixes an existing tree path
Example fix
// before // adding blob "assets" while tree assets/ exists fileChange = new FileChange(FileOperation.ADD, "assets", blobId); // after fileChange = new FileChange(FileOperation.ADD, "assets/logo.png", blobId); // unique path
Defensive patterns
Strategy: validation
Validate before calling
// caller-side check: no new file path collides with an existing tree
boolean collidesWithDir = existingTreePaths.stream()
.anyMatch(p -> p.equals(newFilePath)); // p is a known directory entry
if (collidesWithDir)
throw new IllegalArgumentException("Path collides with existing directory: " + newFilePath); Try / catch
try {
gitService.commitTreeChanges(...); // or equivalent tree insertion API
} catch (ObjectAlreadyExistsException e) {
// e.getMessage() contains the offending path: rename or split commits
} Prevention
- Check the target tree before adding files: a path may already be a directory
- Split 'delete directory + add file of same name' into two commits
- Watch for case-insensitive/case-sensitive path mismatches
When it happens
Trigger: Calling DefaultGitService methods that add/update files (e.g. commit file changes or create trees) where the change set contains a file whose path collides with an existing directory in the target tree — e.g. adding blob 'docs' when tree 'docs/' exists (or a sibling blob named the same in the same commit set).
Common situations: Adding a file named like an existing folder (case-sensitivity edge cases); API/scripts creating files without checking tree layout; committing a changeset that replaces a directory with a file of the same name in one step.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- Path does not represent a tree: " + treeWalk.getPathString()
- 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:
- No default branch in project:
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/1f2420807a5d5de7.
Report an issue: GitHub.