{"record":{"id":"c7759f89dbeea20b","repo":"theonedev/onedev","slug":"no-permission-to-write-code-in-issue-project","errorCode":null,"errorMessage":"No permission to write code in issue project","messagePattern":"No permission to write code in issue project","errorType":"http","errorClass":"UnauthorizedException","httpStatus":403,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/TodResource.java","lineNumber":487,"sourceCode":"            throw new NotFoundException(\"Issue not found: \" + referenceString);\n        }\n    }\n    \n    @Path(\"/get-issue\")\n    @GET\n    public Map<String, Object> getIssueDetail(\n                @QueryParam(\"currentProject\") @NotNull String currentProjectPath, \n                @QueryParam(\"reference\") @NotNull String issueReference, \n                @QueryParam(\"forWrite\") Boolean forWrite) {\n        var subject = SecurityUtils.getSubject();\n        if (SecurityUtils.getUser(subject) == null)\n            throw new UnauthenticatedException();\n\n        var currentProject = getProject(currentProjectPath);\n        var issue = getIssue(currentProject, issueReference);                \n\n        if (forWrite != null && forWrite &&!SecurityUtils.canWriteCode(issue.getProject()))\n            throw new UnauthorizedException(\"No permission to write code in issue project\");\n\n        return IssueHelper.getDetail(currentProject, issue);\n    }\n\n    @Path(\"/query-projects\")\n    @GET\n    public List<Map<String, Object>> queryProjects(\n                @QueryParam(\"query\") String query,\n                @QueryParam(\"offset\") int offset,\n                @QueryParam(\"count\") int count) {\n        var subject = SecurityUtils.getSubject();\n        if (SecurityUtils.getUser(subject) == null)\n            throw new UnauthenticatedException();\n\n        if (count > RestConstants.MAX_PAGE_SIZE)\n            throw new NotAcceptableException(\"Count should not be greater than \" + RestConstants.MAX_PAGE_SIZE);\n\n        var parsedQuery = ProjectQuery.parse(query);","sourceCodeStart":469,"sourceCodeEnd":505,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/TodResource.java#L469-L505","documentation":"getIssueDetail throws UnauthorizedException with this message when the caller passes forWrite=true but the authenticated user cannot write code in the issue's project (SecurityUtils.canWriteCode fails). Write-oriented AI operations are restricted to users with commit/write access.","triggerScenarios":"Calling GET /get-issue with forWrite=true where the authenticated user's role in issue.getProject() lacks code-write permission.","commonSituations":"An AI agent requesting write access for a user who is only a reader; using a read-only CI/service token; user recently downgraded to a role without write access.","solutions":["Call with forWrite=false (or omit) if only read access is needed.","Grant the user (or token owner) a role with code-write permission in the issue's project.","Use an access token from a user who is a committer/maintainer in that project."],"exampleFix":"// before\nGET /api/tod/get-issue?currentProject=p&reference=p#1&forWrite=true\n// after (read-only)\nGET /api/tod/get-issue?currentProject=p&reference=p#1&forWrite=false","handlingStrategy":"validation","validationCode":"// only request write when the user actually has code-write access\nconst forWrite = needsWrite && userCanWriteCode(issueProject, currentUser);\nconst params = { currentProject, reference, forWrite };","typeGuard":null,"tryCatchPattern":"try {\n  return await getIssueDetail(params);\n} catch (e) {\n  if (isUnauthorizedError(e) && /write code/.test(e.message)) {\n    return getIssueDetail({ ...params, forWrite: false });\n  }\n  throw e;\n}","preventionTips":["Request forWrite=true only when the operation truly needs write access.","Keep service tokens mapped to roles with the required write permissions.","Audit role assignments when integrations start failing with permission errors."],"tags":["rest","authorization","permissions"],"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"}