{"record":{"id":"4f266f44b6fb5b58","repo":"theonedev/onedev","slug":"specified-path-is-not-a-directory-blobident-pat","errorCode":null,"errorMessage":"Specified path is not a directory: ${blobIdent.path}","messagePattern":"Specified path is not a directory: (.+?)","errorType":"http","errorClass":"NotAcceptableException","httpStatus":406,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java","lineNumber":325,"sourceCode":"\t\treturn EnumSet.allOf(LogCommand.Field.class).stream().map(Enum::name).collect(toList());\n\t}\n\t\n\t@Api(order=90, description=\"Get children of specified directory\")\n\t@Path(\"/{projectId}/directories/{revisionAndDirectory:.*}\")\n\t@GET\n\tpublic List<DirectoryChild> getDirectory(\n\t\t\t@PathParam(\"projectId\") Long projectId, \n\t\t\t@PathParam(\"revisionAndDirectory\") @NotEmpty @Api(example=\"some-branch-or-tag/path/to/directory\") String revisionAndDirectory) {\n\t\tProject project = projectService.load(projectId);\n\t\tif (!SecurityUtils.canReadCode(project)) {\n\t\t\tthrow new UnauthorizedException();\n\t\t}\n\n\t\tList<String> revisionAndPathSegments = Splitter.on('/').splitToList(revisionAndDirectory);\n\t\tBlobIdent blobIdent = new BlobIdent(project, revisionAndPathSegments);\n\n\t\tif (!blobIdent.isTree()) {\n\t\t\tthrow new NotAcceptableException(\"Specified path is not a directory: \" + blobIdent.path);\n\t\t}\n\n\t\tObjectId revId = project.getObjectId(blobIdent.revision, true);\n\t\t\n\t\tList<DirectoryChild> children = new ArrayList<>();\n\t\tfor (BlobIdent childIdent: gitService.getChildren(\n\t\t\t\tproject, revId, blobIdent.path, BlobIdentFilter.ALL, false)) {\n\t\t\tDirectoryChild child = new DirectoryChild();\n\t\t\tchild.path = childIdent.path;\n\t\t\tchild.isFile = (FileMode.TYPE_MASK & childIdent.mode) == FileMode.TYPE_FILE;\n\t\t\tchildren.add(child);\n\t\t}\n\t\t\n\t\treturn children;\n\t}\n\t\n\t@Api(order=100, description=\"Get metadata and content of specified file\")\n\t@Path(\"/{projectId}/files/{revisionAndFile:.*}\")","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java#L307-L343","documentation":"RepositoryResource.getDirectory parses the 'revisionAndDirectory' path parameter into a BlobIdent and requires it to designate a tree. If the path actually points to a blob (file) rather than a directory, it throws a NotAcceptableException with message \"Specified path is not a directory: <path>\".","triggerScenarios":"GET .../files/{revisionAndDirectory} where the path portion of revisionAndDirectory names a file (e.g. 'main/src/App.java') instead of a directory ('main/src').","commonSituations":"Clients walking a tree that mistakenly pass file entries returned by a previous listing; trailing-path bugs that drop or misplace the directory segment; confusing a symlink/file with a folder.","solutions":["Point the path at a directory — drop any trailing file segment (request 'main/src' not 'main/src/App.java').","If you need file contents, call the getFile endpoint instead of getDirectory.","When walking listings programmatically, branch on the entry type returned by DirectoryChild (file vs directory) before recursing."],"exampleFix":"// before\ncurl .../projects/42/files/main/README.md   // file path\n\n// after\ncurl .../projects/42/files/main             // directory path","handlingStrategy":"validation","validationCode":"// when walking listings, only recurse into directory children\nif (child.type === \"directory\") {\n  await getDirectory(projectId, `${revision}/${child.path}`);\n}","typeGuard":"function isDirectoryPath(p) { return !path.extname(p) || p.endsWith(\"/\"); } // heuristic; confirm via listing","tryCatchPattern":"try {\n  return await getDirectory(projectId, revAndDir);\n} catch (e) {\n  if (isNotAcceptable(e) && /not a directory/.test(e.message)) {\n    return await getFile(projectId, revAndDir); // fallback to file read\n  }\n  throw e;\n}","preventionTips":["Branch on the child type returned by DirectoryChild before recursing.","Strip file segments from paths before calling the directory endpoint.","Remember the endpoint expects 'revision/directory', not 'revision/file'."],"tags":["rest-api","git","path-validation"],"backgroundTag":"path-is-not-a-directory","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}