{"record":{"id":"22982474a251b044","repo":"theonedev/onedev","slug":"cannot-set-ai-setting-for-non-ai-account","errorCode":null,"errorMessage":"Cannot set AI setting for non AI account","messagePattern":"Cannot set AI setting for non AI account","errorType":"http","errorClass":"ExplicitException","httpStatus":400,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java","lineNumber":520,"sourceCode":"\t\t\t} else {\n\t\t\t\tuser.setPassword(passwordService.encryptPassword(password));\n\t\t\t\tuserService.update(user, null);\n\t\t\t\treturn Response.ok().build();\n\t\t\t}\t\t\t\n    \t} else {\n\t\t\tthrow new UnauthorizedException();\n\t\t}\n    }\n\n\t@Api(order=2000)\n\t@Path(\"/{userId}/ai-setting\")\n    @POST\n    public Response setAiSetting(@PathParam(\"userId\") Long userId, @NotNull AiSetting aiSetting) {\n    \tUser user = userService.load(userId);\n\t\tif (user.isDisabled()) {\n\t\t\tthrow new ExplicitException(\"Cannot set password for disabled account\");\n\t\t} else if (user.getType() != AI) {\n\t\t\tthrow new ExplicitException(\"Cannot set AI setting for non AI account\");\n\t\t} else if (SecurityUtils.isAdministrator()) {\n\t\t\tuser.setAiSetting(aiSetting);\n\t\t\tuserService.update(user, null);\n\t\t\tif (!getAuthUser().equals(user)) \n\t\t\t\tauditService.audit(null, \"changed AI setting of account \\\"\" + user.getName() + \"\\\" via RESTful API\", null, null);\n\t\t\treturn Response.ok().build();\t\n\t\t} else if (user.equals(getAuthUser())) {\n\t\t\tuser.setAiSetting(aiSetting);\n\t\t\tuserService.update(user, null);\n\t\t\treturn Response.ok().build();\n    \t} else {\n\t\t\tthrow new UnauthorizedException();\n\t\t}\n    }\n\n\t@Api(order=2025)\n\t@Path(\"/{userId}/two-factor-authentication\")\n\t@DELETE","sourceCodeStart":502,"sourceCodeEnd":538,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java#L502-L538","documentation":"AI settings can only be applied to accounts of type AI. If the target user's type is not AI (ordinary or service account), the setAiSetting endpoint rejects the request. Ordinary and service accounts do not consume AI features, so attaching an AiSetting to them is invalid.","triggerScenarios":"Calling POST /rest/v1/users/{userId}/ai-setting with the id of a non-AI (ordinary or service) account.","commonSituations":"Scripts iterating all users and applying AI settings unconditionally; confusing user ids between an AI bot account and a human account; provisioning templates applied to all accounts.","solutions":["Verify user.getType() == AI before posting AI settings","Only include AI-type accounts in AI configuration scripts","Create/use a dedicated AI account for AI settings rather than applying them to user accounts"],"exampleFix":"// before\nawait rest.post(`/users/${id}/ai-setting`, aiSetting); // 400: not AI\n// after\nconst user = await rest.get(`/users/${id}`);\nif (user.type === 'AI') {\n  await rest.post(`/users/${id}/ai-setting`, aiSetting);\n}","handlingStrategy":"validation","validationCode":"const user = await rest.get(`/users/${userId}`); if (user.type !== 'AI') throw new Error('AI settings can only be set on AI accounts');","typeGuard":"function isAiAccount(user) { return user.type === 'AI'; }","tryCatchPattern":"try { await rest.post(`/users/${id}/ai-setting`, aiSetting); } catch (e) { if (e.status === 400 && /non AI account/.test(e.message)) { /* wrong account type, skip */ } else throw e; }","preventionTips":["Only post AI settings to AI-type accounts","Maintain a separate inventory of AI/bot accounts","Verify account type before applying AI configuration"],"tags":["rest-api","ai-account","account-type","onedev"],"backgroundTag":"invalid-argument-value","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"}