{"record":{"id":"6f283658aa646691","repo":"theonedev/onedev","slug":"specified-path-is-not-a-file-blobident-path","errorCode":null,"errorMessage":"Specified path is not a file: ${blobIdent.path}","messagePattern":"Specified path is not a file: (.+?)","errorType":"http","errorClass":"NotAcceptableException","httpStatus":406,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java","lineNumber":357,"sourceCode":"\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:.*}\")\n\t@GET\n\tpublic FileResponse getFile(\n\t\t\t@PathParam(\"projectId\") Long projectId, \n\t\t\t@PathParam(\"revisionAndFile\") @NotEmpty @Api(example=\"some-branch-or-tag/path/to/file\") String revisionAndFile) {\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(revisionAndFile);\n\t\tBlobIdent blobIdent = new BlobIdent(project, revisionAndPathSegments);\n\n\t\tif (!blobIdent.isFile()) {\n\t\t\tthrow new NotAcceptableException(\"Specified path is not a file: \" + blobIdent.path);\n\t\t}\n\n\t\tBlob blob = project.getBlob(blobIdent, true);\n\n\t\tFileResponse response = new FileResponse();\n\t\tresponse.path = blobIdent.path;\n\t\tresponse.sha = blob.getBlobId().name();\n\t\tresponse.base64Content = new String(Base64.encodeBase64(blob.getBytes()));\n\t\tresponse.size = blob.getSize();\n\t\tresponse.isPartial = blob.isPartial();\n\t\treturn response;\n\t}\n\t\n\t@Api(order=110, description=\"Create, update, or delete specified file. Return hash of resulting commit\", \n\t\t\texample=\"46c001b04cba0ca41588841f1ca32f50b582ee9b\")\n\t@Path(\"/{projectId}/files/{branchAndFile:.*}\")\n\t@POST\n\tpublic FileEditResponse editFile(","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java#L339-L375","documentation":"RepositoryResource.getFile parses the 'revisionAndFile' path parameter into a BlobIdent and requires it to designate a file (blob). If the path points to a directory rather than a file, it throws a NotAcceptableException with message \"Specified path is not a file: <path>\".","triggerScenarios":"GET .../files/{revisionAndFile} where the path portion names a directory (e.g. 'main/src') instead of an actual file.","commonSituations":"Generic download-file scripts pointed at a folder URL; hardcoding paths that later became directories after refactoring; confusion between the file and directory endpoints.","solutions":["Append the exact file name to the path ('main/src/App.java' instead of 'main/src').","Use getDirectory when you need the folder listing rather than file contents.","Validate the target path resolves to a blob (e.g. via the directory listing) before requesting contents."],"exampleFix":"// before\ncurl .../projects/42/files/main/src  // directory\n\n// after\ncurl .../projects/42/files/main/src/App.java","handlingStrategy":"validation","validationCode":"// ensure the path has a file segment before requesting contents\nif (!revisionAndFile.includes(\"/\") || pathEndsInDirectory(revisionAndFile)) {\n  throw new Error(\"Provide a full file path: revision/path/to/file\");\n}","typeGuard":"function isFilePath(p) { return typeof p === \"string\" && /\\.[A-Za-z0-9]+$/.test(p.split('/').pop() || \"\"); }","tryCatchPattern":"try {\n  return await getFile(projectId, revisionAndFile);\n} catch (e) {\n  if (isNotAcceptable(e) && /not a file/.test(e.message)) {\n    return await getDirectory(projectId, revisionAndFile); // it is a folder\n  }\n  throw e;\n}","preventionTips":["Append the exact file name including extension to the revision.","Use the directory endpoint when the target is a folder.","Validate paths against a prior directory listing before fetching."],"tags":["rest-api","git","path-validation"],"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-14T00:17:10.932Z"}