{"record":{"id":"fe39205f6b4b513f","repo":"theonedev/onedev","slug":"no-permission-to-update-issue-description","errorCode":null,"errorMessage":"No permission to update issue description","messagePattern":"No permission to update issue description","errorType":"http","errorClass":"UnauthorizedException","httpStatus":403,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/TodResource.java","lineNumber":610,"sourceCode":"        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) {\n            if (!subscriptionService.isSubscriptionActive())\n                throw new NotAcceptableException(\"An active subscription is required for this feature\");\n            if (!issue.getProject().isTimeTracking())\n                throw new NotAcceptableException(\"Time tracking needs to be enabled for the project\");\n            if (!SecurityUtils.canScheduleIssues(subject, issue.getProject()))\n                throw new UnauthorizedException(\"Issue schedule permission required to set own estimated time\");","sourceCodeStart":592,"sourceCodeEnd":628,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/TodResource.java#L592-L628","documentation":"editIssue guards the \"description\" field with the same canModifyIssue check; if it fails, UnauthorizedException(\"No permission to update issue description\") is thrown. The user is authenticated but not authorized to modify this issue.","triggerScenarios":"Sending {\"description\": ...} in the edit-issue data map while the user lacks issue-modify permission on the target issue/project, or the issue is confidential to them.","commonSituations":"Bulk-update scripts iterating issues across projects with differing permissions; token owners whose role downgraded; AI tools updating issues in projects the user can only read.","solutions":["Confirm the user can edit the issue in the OneDev UI; if not, obtain Edit Issue permission for the project.","Exclude the \"description\" key when the user lacks permission, splitting the update into permitted fields.","For confidential issues, have an admin grant access or use an authorized account/token.","Pre-check permissions by fetching issue detail and only including fields the caller may modify."],"exampleFix":"// before\neditIssue(project, ref, {description: \"Updated\"}) // 403\n// after\nif (canEdit) editIssue(project, ref, {description: \"Updated\"})","handlingStrategy":"validation","validationCode":"if ('description' in payload && !canModifyIssue) delete payload.description;\nif (!canModifyIssue && Object.keys(payload).length) throw new Error('No permission to modify this issue');","typeGuard":null,"tryCatchPattern":"try { await editIssue(project, ref, payload); } catch (e) { if (e.status === 403 && /description/.test(e.message)) { log('Permission denied for description update'); return partialUpdate(); } throw e; }","preventionTips":["Verify modify permission on the exact issue (project role + confidentiality) first","Prefetch issue detail to learn what the user may change","Keep automation tokens scoped to accounts with edit rights","Handle 403 field-specific messages to degrade gracefully"],"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-14T00:17:10.932Z"}