{"record":{"id":"8994c2b6672eb21f","repo":"theonedev/onedev","slug":"issue-schedule-permission-required-to-set-own-esti","errorCode":null,"errorMessage":"Issue schedule permission required to set own estimated time","messagePattern":"Issue schedule permission required to set own estimated time","errorType":"exception","errorClass":"UnauthorizedException","httpStatus":401,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/IssueHelper.java","lineNumber":291,"sourceCode":"        var title = (String) data.remove(\"title\");\n        if (title == null)\n            throw new ExplicitException(\"Title is required\");\n        issue.setTitle(title);\n        var description = (String) data.remove(\"description\");\n        issue.setDescription(description);\n        var confidential = (Boolean) data.remove(\"confidential\");\n        if (confidential != null)\n            issue.setConfidential(confidential);\n\n        Integer ownEstimatedTime = (Integer) data.remove(\"ownEstimatedTime\");\n        if (ownEstimatedTime != null) {\n            var subscriptionService = OneDev.getInstance(SubscriptionService.class);\n            if (!subscriptionService.isSubscriptionActive())\n                throw new ExplicitException(\"An active subscription is required for this feature\");\n            if (!project.isTimeTracking())\n                throw new ExplicitException(\"Time tracking needs to be enabled for the project\");\n            if (!SecurityUtils.canScheduleIssues(subject, project))\n                throw new UnauthorizedException(\"Issue schedule permission required to set own estimated time\");\n            issue.setOwnEstimatedTime(ownEstimatedTime * 60);\n        }\n\n        List<String> iterationNames = (List<String>) data.remove(\"iterations\");\n        if (iterationNames != null) {\n            if (!SecurityUtils.canScheduleIssues(subject, project))\n                throw new UnauthorizedException(\"Issue schedule permission required to set iterations\");\n            var iterationService = OneDev.getInstance(IterationService.class);\n            for (var iterationName : iterationNames) {\n                var iteration = iterationService.findInHierarchy(project, iterationName);\n                if (iteration == null)\n                    throw new ExplicitException(\"Iteration '\" + iterationName + \"' not found\");\n                IssueSchedule schedule = new IssueSchedule();\n                schedule.setIssue(issue);\n                schedule.setIteration(iteration);\n                issue.getSchedules().add(schedule);\n            }\n        }","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/IssueHelper.java#L273-L309","documentation":"Setting ownEstimatedTime requires the acting subject to have schedule-issues permission on the project. createIssue throws UnauthorizedException when SecurityUtils.canScheduleIssues(subject, project) is false.","triggerScenarios":"A user (or AI acting on their behalf) without issue-schedule permission submits an \"ownEstimatedTime\" value in createIssue.","commonSituations":"Service accounts or restricted roles used in automation; AI tools executing with the end user's permissions; permission role changes removed 'Schedule issues' from the user's role.","solutions":["Grant the user's role the 'Schedule issues' permission on the project (Project > Access/Authorization)","Use an account with schedule permission for the automation","Remove \"ownEstimatedTime\" from the payload when the actor lacks the permission"],"exampleFix":"// before: low-privilege token sets estimated time -> UnauthorizedException\ndata.put(\"ownEstimatedTime\", 2);\n// after: check first\nif (SecurityUtils.canScheduleIssues(subject, project)) data.put(\"ownEstimatedTime\", 2);","handlingStrategy":"validation","validationCode":"if (data.containsKey(\"ownEstimatedTime\")\n        && !SecurityUtils.canScheduleIssues(subject, project))\n    throw new SecurityException(\"Actor lacks schedule-issues permission\");","typeGuard":null,"tryCatchPattern":"try {\n    issueHelper.createIssue(project, subject, data);\n} catch (UnauthorizedException e) {\n    if (e.getMessage().contains(\"schedule permission\")) {\n        // rerun as privileged account or drop the field\n    }\n}","preventionTips":["Grant 'Schedule issues' permission to automation accounts","Check canScheduleIssues before including schedule-related fields","Audit role permissions after project changes"],"tags":["authorization","permissions","time-tracking"],"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"}