theonedev/onedev · error · ObjectAlreadyExistsException
Overlapped blob path: " + blobPath
Error message
Overlapped blob path: " + blobPath
What it means
When inserting new blobs in a single commit, DefaultGitService rejects a request where a new file path (e.g. 'file.txt') collides with the top-level segment of another new nested path (e.g. 'file.txt/sub/file') — git cannot hold both a file and a directory with the same name. The overlap is detected by comparing top-level segments of new paths against new top-level files and ObjectAlreadyExistsException is thrown.
Source
Thrown at server-core/src/main/java/io/onedev/server/git/service/DefaultGitService.java:773
Set<String> files = new HashSet<>();
for (Map.Entry<String, BlobContent> entry : currentNewBlobs.entrySet()) {
String path = entry.getKey();
if (!path.contains("/")) {
files.add(path);
entries.add(new TreeFormatterEntry(path, entry.getValue().getMode(),
inserter.insert(Constants.OBJ_BLOB, entry.getValue().getBytes())));
files.add(path);
}
}
Set<String> topLevelPathSegments = new LinkedHashSet<>();
for (String path : currentNewBlobs.keySet()) {
if (path.contains("/")) {
String topLevelPathSegment = StringUtils.substringBefore(path, "/");
if (files.contains(topLevelPathSegment)) {
String blobPath = topLevelPathSegment;
if (parentPath != null)
blobPath = parentPath + "/" + path;
throw new ObjectAlreadyExistsException("Overlapped blob path: " + blobPath);
} else {
topLevelPathSegments.add(topLevelPathSegment);
}
}
}
for (String topLevelPathSegment : topLevelPathSegments) {
Map<String, BlobContent> childNewBlobs = new HashMap<>();
for (Map.Entry<String, BlobContent> entry : currentNewBlobs.entrySet()) {
String path = entry.getKey();
if (path.startsWith(topLevelPathSegment + "/"))
childNewBlobs.put(path.substring(topLevelPathSegment.length() + 1), entry.getValue());
}
if (parentPath == null)
parentPath = topLevelPathSegment;
else
parentPath += "/" + topLevelPathSegment;
ObjectId childTreeId = insertTree(revTree, treeWalk, inserter, parentPath,
Sets.newHashSet(), childNewBlobs);View on GitHub (pinned to d44925c47c)
Solutions
- Rename either conflicting path so no name is used both as a file and as a directory in the same commit.
- Split into two commits: first remove the file that must become a directory, then add the nested files.
- Validate the new blob path set before committing: no path P and P/… may coexist.
Example fix
// before
edits.addNewBlob("config", ...);
edits.addNewBlob("config/app.yml", ...); // conflict
// after
String file = "config", dir = "config/app.yml";
if (dir.startsWith(file + "/")) throw new IllegalArgumentException(file + " cannot be both file and directory"); Defensive patterns
Strategy: validation
Validate before calling
Set<String> files = newBlobs.keySet().stream().filter(p -> !p.contains("/")).collect(Collectors.toSet());
boolean conflict = newBlobs.keySet().stream().anyMatch(p -> p.contains("/") && files.contains(StringUtils.substringBefore(p, "/")));
if (conflict) throw new IllegalArgumentException("A new path is used both as file and directory"); Try / catch
try { commitBlobs(edits); } catch (ObjectAlreadyExistsException e) { log.error("Overlapping paths in batch: {}", e.getMessage()); } Prevention
- Validate the new-path set for file/dir overlaps before submitting
- Generate programmatic file trees through a single naming scheme
- Split file-removal and directory-creation into separate commits
When it happens
Trigger: Committing a batch of new blobs (BlobEdits.newBlobs) via the git service where one new path is a plain file 'X' and another new path starts with 'X/', in the same request.
Common situations: Bulk uploads/imports generating file trees programmatically where one component is both a file and a directory; adding a directory of files under a name that already exists as a file in the same batch; CI-generated configs writing both 'module' and 'module/x' paths.
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
- 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:
- Ref not found (project:
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/f632229771a9c9f8.
Report an issue: GitHub.