{"record":{"id":"352f1da9d6af7722","repo":"theonedev/onedev","slug":"path-blobident-path-is-a-tree","errorCode":null,"errorMessage":"Path '\" + blobIdent.path + \"' is a tree\"","messagePattern":"Path '\" \\+ blobIdent\\.path \\+ \"' is a tree\"","errorType":"exception","errorClass":"BadRequestException","httpStatus":null,"severity":"warning","filePath":"server-core/src/main/java/io/onedev/server/git/service/DefaultGitService.java","lineNumber":942,"sourceCode":"\t\t\t\treturn submodules;\n\t\t\t}\n\n\t\t\tprivate Blob getBlob(String path) {\n\t\t\t\tRepository repository = getRepository(projectId);\n\t\t\t\ttry (RevWalk revWalk = new RevWalk(repository)) {\n\t\t\t\t\tBlob blob = null;\n\t\t\t\t\tRevCommit commit = GitUtils.parseCommit(revWalk, revId);\n\t\t\t\t\tif (commit != null) {\n\t\t\t\t\t\tTreeWalk treeWalk = TreeWalk.forPath(repository, path, commit.getTree());\n\t\t\t\t\t\tif (treeWalk != null) {\n\t\t\t\t\t\t\tBlobIdent blobIdent = new BlobIdent(revId.name(), path, treeWalk.getRawMode(0));\n\t\t\t\t\t\t\tObjectId blobId = treeWalk.getObjectId(0);\n\t\t\t\t\t\t\tif (blobIdent.isGitLink()) {\n\t\t\t\t\t\t\t\tString url = getSubmodules().get(blobIdent.path);\n\t\t\t\t\t\t\t\tString hash = blobId.name();\n\t\t\t\t\t\t\t\tblob = new Blob(blobIdent, blobId, new Submodule(url, hash).toString().getBytes());\n\t\t\t\t\t\t\t} else if (blobIdent.isTree()) {\n\t\t\t\t\t\t\t\tthrow new BadRequestException(\"Path '\" + blobIdent.path + \"' is a tree\");\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tblob = new Blob(blobIdent, blobId, treeWalk.getObjectReader());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn blob;\n\t\t\t\t} catch (IOException e) {\n\t\t\t\t\tthrow new RuntimeException(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic Blob call() {\n\t\t\t\treturn getBlob(path);\n\t\t\t}\n\n\t\t});\n\t}","sourceCodeStart":924,"sourceCodeEnd":960,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/git/service/DefaultGitService.java#L924-L960","documentation":"getBlob in DefaultGitService resolves a path in a commit's tree and returns file content. If the path resolves to a tree (directory) rather than a blob or gitlink, there is no blob content to return, so a BadRequestException is thrown stating the path is a tree. Callers are expected to pass file paths, not directory paths.","triggerScenarios":"Calling getBlob/BlobService.getBlob with a path that exists in the revision as a directory, e.g. requesting blob content for 'src' when 'src' is a folder, or passing an empty/root-like path.","commonSituations":"API clients assuming every path is a file; web UI deep-links to a path that was later converted from file to directory; scripted downloads iterating paths without checking entry type; typos where a trailing file name is missing.","solutions":["Check the path's type first (tree vs blob, e.g. BlobIdent.isTree()) and only fetch blobs for files.","If a directory was intended, enumerate its children instead of requesting blob content.","Fix the path to point to an actual file inside the directory."],"exampleFix":"// before\nBlob blob = blobService.getBlob(projectId, revision, path); // path may be a dir\n// after\nBlobIdent ident = blobService.getBlobIdent(projectId, revision, path);\nif (ident != null && ident.isTree()) throw new BadRequestException(path + \" is a directory, not a file\");\nBlob blob = blobService.getBlob(projectId, revision, path);","handlingStrategy":"type-guard","validationCode":"BlobIdent ident = blobService.getBlobIdent(projectId, revision, path);\nif (ident == null || ident.isTree()) throw new BadRequestException(path + \" is not a file at \" + revision);","typeGuard":"function isFileBlob(ident) { return ident != null && !ident.isTree() && !ident.isGitLink(); }","tryCatchPattern":"try { return blobService.getBlob(projectId, revision, path); } catch (BadRequestException e) { return listTreeChildren(revision, path); }","preventionTips":["Resolve the blob ident and check isTree() before requesting content","Never pass directory paths or the empty path to getBlob","Handle file->directory transitions when pathing against old revisions"],"tags":["git","blob","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}