{"record":{"id":"8100e6cb0cd12f9e","repo":"theonedev/onedev","slug":"no-permission-to-update-issue-title","errorCode":null,"errorMessage":"No permission to update issue title","messagePattern":"No permission to update issue title","errorType":"http","errorClass":"UnauthorizedException","httpStatus":403,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/TodResource.java","lineNumber":604,"sourceCode":"                @QueryParam(\"currentProject\") @NotNull String currentProjectPath, \n                @QueryParam(\"reference\") @NotNull String issueReference, \n                @NotNull Map<String, Serializable> data) {\n        var subject = SecurityUtils.getSubject();\n        var user = SecurityUtils.getUser(subject);\n\n        if (user == null)\n            throw new UnauthenticatedException();\n\n        var currentProject = getProject(currentProjectPath);\n\n        var issue = getIssue(currentProject, issueReference);\n\n        IssueHelper.normalizeData(data);\n\n        var title = (String) data.remove(\"title\");\n        if (title != null) { \n            if (!SecurityUtils.canModifyIssue(subject, issue))\n                throw new UnauthorizedException(\"No permission to update issue title\");\n            issueChangeService.changeTitle(user, issue, title);\n        }\n\n        if (data.containsKey(\"description\")) {\n            if (!SecurityUtils.canModifyIssue(subject, issue))\n                throw new UnauthorizedException(\"No permission to update issue description\");\n            issueChangeService.changeDescription(user, issue, (String) data.remove(\"description\"));\n        }\n\n        var confidential = (Boolean) data.remove(\"confidential\");\n        if (confidential != null) {\n            if (!SecurityUtils.canModifyIssue(subject, issue))\n                throw new UnauthorizedException(\"No permission to update issue confidential\");\n            issueChangeService.changeConfidential(user, issue, confidential);\n        }\n\n        Integer ownEstimatedTime = (Integer) data.remove(\"ownEstimatedTime\");\n        if (ownEstimatedTime != null) {","sourceCodeStart":586,"sourceCodeEnd":622,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/TodResource.java#L586-L622","documentation":"editIssue allows changing the title only if SecurityUtils.canModifyIssue(subject, issue) is true; otherwise it throws UnauthorizedException with \"No permission to update issue title\". This is a per-issue authorization check (considers project roles and issue-level permissions like confidential issues), not an authentication problem.","triggerScenarios":"Including the \"title\" key in the data map passed to POST /edit-issue while the authenticated user lacks modify permission on that issue (e.g. read-only role, confidential issue, non-member of the project).","commonSituations":"AI assistants auto-generating edits on issues the user can only view; service tokens of accounts with Reporter-only access; editing a confidential issue as an outsider.","solutions":["Remove the \"title\" key from the request data if only viewing permission is available, or request project permission that allows issue modification.","Ask a project admin to grant the user Edit Issue access on the project (or the specific confidential issue).","Verify the issue isn't confidential for this user; if it must be edited, use an account with the necessary role.","Test with a user who can edit the issue in the web UI to confirm the permission model, then align API usage."],"exampleFix":"// before\neditIssue(project, ref, {title: \"New title\", description: \"x\"}) // no modify perm\n// after\neditIssue(project, ref, {description: \"x\"}) // only fields user may change","handlingStrategy":"validation","validationCode":"// only include fields the user may change\nconst canEdit = issueDetail.permission && issueDetail.permission.modify;\nconst payload = canEdit ? {title} : {};\nif (title !== undefined && !canEdit) throw new Error('Skipping title change: no modify permission');","typeGuard":null,"tryCatchPattern":"try { await editIssue(project, ref, {title}); } catch (e) { if (e.status === 403 && /title/.test(e.message)) { notifyAdmin('Grant Edit Issue permission'); } else throw e; }","preventionTips":["Check the user can edit the issue in the web UI before API edits","Split updates per-field so one forbidden field doesn't block others","Watch for confidential issues: they often deny modification","Use tokens of accounts with adequate project roles for automation"],"tags":["authorization","permissions","http-403","issue-edit"],"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"}