{"record":{"id":"79567487191dcf8b","repo":"theonedev/onedev","slug":"permission-denied-calling-tool","errorCode":null,"errorMessage":"Permission denied calling tool: ","messagePattern":"Permission denied calling tool: ","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/ai/ToolUtils.java","lineNumber":98,"sourceCode":"\t\t}\n\t\treturn convertToJson(Map.of(\"successful\", true, \"filesAndFolders\", filesAndFolders));\n\t}\n\n\tpublic static JsonNode getToolArguments(ToolExecutionRequest toolExecutionRequest) {\n\t\tvar objectMapper = getObjectMapper();\n\t\tif (toolExecutionRequest.arguments() == null)\n\t\t\treturn objectMapper.createObjectNode();\n\n\t\ttry {\n\t\t\treturn objectMapper.readTree(toolExecutionRequest.arguments());\n\t\t} catch (JsonProcessingException e) {\n\t\t\tthrow new RuntimeException(e);\n\t\t}\n\t}\n\n\tpublic static void handleCallException(String toolName, Throwable exception) {\n\t\tif (ExceptionUtils.find(exception, UnauthorizedException.class) != null) \n\t\t\tthrow new ExplicitException(\"Permission denied calling tool: \" + toolName);\n\t\tvar explicitException = ExceptionUtils.find(exception, ExplicitException.class);\n\t\tif (explicitException != null) \n\t\t\tthrow explicitException;\n\t\tlogger.error(\"Error calling tool: \" + toolName, exception);\n\t\tthrow new ExplicitException(\"Error calling tool '\" + toolName + \"', check server log for details\");\n\t}\n\n\tpublic static ChatTool wrapForChat(TaskTool taskTool) {\n\t\treturn new ChatTool() {\n\n\t\t\t@Override\n\t\t\tpublic ToolSpecification getSpecification() {\n\t\t\t\treturn taskTool.getSpecification();\n\t\t\t}\n\n\t\t\t@Override\n\t\t\tpublic CompletableFuture<ToolExecutionResult> execute(@Nullable IPartialPageRequestHandler handler, Subject subject, JsonNode arguments) {\n\t\t\t\treturn CompletableFuture.completedFuture(taskTool.execute(subject, arguments));","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/ai/ToolUtils.java#L80-L116","documentation":"ToolUtils.handleCallException converts any UnauthorizedException found in a tool-call exception chain into an ExplicitException 'Permission denied calling tool: <name>'. This is the AI tool layer's way of surfacing authorization failures from underlying services to the chat user.","triggerScenarios":"Any AI tool invocation whose execution path throws UnauthorizedException — e.g. the agent's user lacks project access required by the tool (reading issues, triggering builds, accessing code).","commonSituations":"AI agent operating as a user without membership in the target project; revoked permissions mid-session; tools accessing private projects.","solutions":["Grant the authenticated user the permissions needed for the specific tool's operations in OneDev.","Run the AI integration under a service account with the appropriate project roles.","Narrow tool usage to projects the user can access."],"exampleFix":"// before\n// user 'bot' has no role on project 'core'\nchatClient.call(\"listIssues\", Map.of(\"project\", \"core\"));\n// after\n// add 'bot' as a member (e.g. Read role) of project 'core', then\nchatClient.call(\"listIssues\", Map.of(\"project\", \"core\"));","handlingStrategy":"try-catch","validationCode":"// verify user's project access before invoking the tool\nconst perms = await getProjectPermissions(user, projectPath);\nif (!perms.canRead) throw new Error(\"User lacks access to project \" + projectPath);","typeGuard":null,"tryCatchPattern":"try { return callTool(name, args); } catch (e) { if (/Permission denied calling tool/.test(e.message)) { await requestAccessOrNotifyUser(name); return null; } throw e; }","preventionTips":["Run AI integrations under a service account with least-required roles","Pre-check permissions for each tool's target project","Catch ExplicitException in the tool layer to surface friendly messages"],"tags":["authorization","permission","ai-tools"],"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"}