{"record":{"id":"44e3ad66ff26e094","repo":"theonedev/onedev","slug":"unauthorized-44e3ad","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/web/resource/PatchResource.java","lineNumber":65,"sourceCode":"\tprotected ResourceResponse newResourceResponse(Attributes attributes) {\n\t\tPageParameters params = attributes.getParameters();\n\t\t\n\t\tLong projectId = params.get(PARAM_PROJECT).toLong();\n\t\tvar oldCommitId = ObjectId.fromString(params.get(PARAM_OLD_COMMIT).toString());\n\t\tvar newCommitId = ObjectId.fromString(params.get(PARAM_NEW_COMMIT).toString());\n\t\tvar forCodeReview = params.get(PARAM_FOR_CODE_REVIEW).toBoolean(false);\n\t\t\n\t\tString excludedFiles;\n\t\tif (forCodeReview) {\n\t\t\tProject project = getProjectService().load(projectId);\n\t\t\texcludedFiles = project.findExcludedAiReviewFiles();\n\t\t} else {\n\t\t\texcludedFiles = null;\n\t\t}\n\t\tif (!SecurityUtils.isSystem()) {\n\t\t\tProject project = getProjectService().load(projectId);\n\t\t\tif (!SecurityUtils.canReadCode(project))\n\t\t\t\tthrow new UnauthorizedException();\n\t\t}\n\n\t\tResourceResponse response = new ResourceResponse();\n\t\t\n\t\tresponse.getHeaders().addHeader(\"X-Content-Type-Options\", \"nosniff\");\n\t\tresponse.setContentType(MimeTypes.OCTET_STREAM);\n\n\t\tresponse.setFileName(URLEncoder.encode(\"changes.patch\", UTF_8));\n\n\t\tresponse.setWriteCallback(new WriteCallback() {\n\n\t\t\t@Override\n\t\t\tpublic void writeData(Attributes attributes) throws IOException {\n\t\t\t\tString activeServer = getProjectService().getActiveServer(projectId, true);\n\t\t\t\tif (activeServer.equals(getClusterService().getLocalServerAddress())) {\n\t\t\t\t\ttry (var os = attributes.getResponse().getOutputStream()) {\n\t\t\t\t\t\tvar repository = getProjectService().getRepository(projectId);\n\t\t\t\t\t\tGitUtils.diff(repository, oldCommitId, newCommitId, excludedFiles, os);","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/web/resource/PatchResource.java#L47-L83","documentation":"PatchResource serves generated patch files for project commits. Outside the system security context it loads the project and throws UnauthorizedException when SecurityUtils.canReadCode(project) is false — patch content is considered code, so code read permission is mandatory. The resource framework returns it as HTTP 401/403 \"Unauthorized\".","triggerScenarios":"GET of the patch resource URL (e.g. /~resource/patches/...) by a user without Read Code permission on the project — anonymous access to a private project, or a role limited to issues/builds.","commonSituations":"Sharing patch links externally while the repository is private; bots/crawlers hitting patch URLs; a formerly public project made private so previously working links start failing.","solutions":["Authenticate as a user with 'Read Code' permission on the project.","Grant the requesting user/role Read Code in project access settings.","If fetching programmatically, use an access token with code read scope."],"exampleFix":"// before: anonymous fetch of patch -> 401\ncurl https://onedev.example.com/~resource/patches/1/abcdef\n// after\ncurl -u user:password https://onedev.example.com/~resource/patches/1/abcdef","handlingStrategy":"validation","validationCode":"// ensure the caller can read code before requesting patches\nif (!userCan('READ_CODE', projectId)) {\n  throw new Error('fetching patches requires Read Code permission on project ' + projectId);\n}","typeGuard":null,"tryCatchPattern":"try { fetchPatch(url); } catch (HttpException e) { if (e.getStatusCode() === 401 || e.getStatusCode() === 403) promptForCredentials(); else throw e; }","preventionTips":["Authenticate before using patch URLs","Update shared links when a project changes from public to private","Give export/report tooling a token with code read access"],"tags":["onedev","http","authorization","git","patches"],"backgroundTag":"permission-denied","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"}