theonedev/onedev · warning · BadRequestException

Path '" + blobIdent.path + "' is a tree"

Error message

Path '" + blobIdent.path + "' is a tree"

What it means

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.

Source

Thrown at server-core/src/main/java/io/onedev/server/git/service/DefaultGitService.java:942

				return submodules;
			}

			private Blob getBlob(String path) {
				Repository repository = getRepository(projectId);
				try (RevWalk revWalk = new RevWalk(repository)) {
					Blob blob = null;
					RevCommit commit = GitUtils.parseCommit(revWalk, revId);
					if (commit != null) {
						TreeWalk treeWalk = TreeWalk.forPath(repository, path, commit.getTree());
						if (treeWalk != null) {
							BlobIdent blobIdent = new BlobIdent(revId.name(), path, treeWalk.getRawMode(0));
							ObjectId blobId = treeWalk.getObjectId(0);
							if (blobIdent.isGitLink()) {
								String url = getSubmodules().get(blobIdent.path);
								String hash = blobId.name();
								blob = new Blob(blobIdent, blobId, new Submodule(url, hash).toString().getBytes());
							} else if (blobIdent.isTree()) {
								throw new BadRequestException("Path '" + blobIdent.path + "' is a tree");
							} else {
								blob = new Blob(blobIdent, blobId, treeWalk.getObjectReader());
							}
						}
					}
					return blob;
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}

			@Override
			public Blob call() {
				return getBlob(path);
			}

		});
	}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Check the path's type first (tree vs blob, e.g. BlobIdent.isTree()) and only fetch blobs for files.
  2. If a directory was intended, enumerate its children instead of requesting blob content.
  3. Fix the path to point to an actual file inside the directory.

Example fix

// before
Blob blob = blobService.getBlob(projectId, revision, path); // path may be a dir
// after
BlobIdent ident = blobService.getBlobIdent(projectId, revision, path);
if (ident != null && ident.isTree()) throw new BadRequestException(path + " is a directory, not a file");
Blob blob = blobService.getBlob(projectId, revision, path);
Defensive patterns

Strategy: type-guard

Validate before calling

BlobIdent ident = blobService.getBlobIdent(projectId, revision, path);
if (ident == null || ident.isTree()) throw new BadRequestException(path + " is not a file at " + revision);

Type guard

function isFileBlob(ident) { return ident != null && !ident.isTree() && !ident.isGitLink(); }

Try / catch

try { return blobService.getBlob(projectId, revision, path); } catch (BadRequestException e) { return listTreeChildren(revision, path); }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/352f1da9d6af7722. Report an issue: GitHub.