{"record":{"id":"0da6dcedccc8b264","repo":"theonedev/onedev","slug":"cannot-set-password-for-service-or-ai-account","errorCode":null,"errorMessage":"Cannot set password for service or AI account","messagePattern":"Cannot set password for service or AI account","errorType":"http","errorClass":"ExplicitException","httpStatus":400,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java","lineNumber":491,"sourceCode":"\t\tif (userId <= User.ROOT_ID)\t\t\n\t\t\tthrow new BadRequestException(\"Should only convert normal users to service accounts\");\n\t\tvar user = userService.load(userId);\n\t\tuserService.convertToServiceAccount(user);\n\n\t\tauditService.audit(null, \"converted user \\\"\" + user.getName() + \"\\\" to service account via RESTful API\", null, null);\n\n\t\treturn Response.ok().build();\n    }\n\t\n\t@Api(order=2000)\n\t@Path(\"/{userId}/password\")\n    @POST\n    public Response setPassword(@PathParam(\"userId\") Long userId, @Password(checkPolicy=true) @NotEmpty String password) {\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() != ORDINARY) {\n\t\t\tthrow new ExplicitException(\"Cannot set password for service or AI account\");\n\t\t} if (SecurityUtils.isAdministrator()) {\n\t\t\tuser.setPassword(passwordService.encryptPassword(password));\n\t\t\tuserService.update(user, null);\n\t\t\tif (!getAuthUser().equals(user)) \n\t\t\t\tauditService.audit(null, \"changed password of account \\\"\" + user.getName() + \"\\\" via RESTful API\", null, null);\n\t\t\treturn Response.ok().build();\n\t\t} else if (user.equals(getAuthUser())) {\n\t\t\tif (user.getPassword() == null) {\n\t\t\t\tthrow new ExplicitException(\"The user is currently authenticated via external system, \"\n\t\t\t\t\t\t+ \"please change password there instead\");\n\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}","sourceCodeStart":473,"sourceCodeEnd":509,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/UserResource.java#L473-L509","documentation":"Passwords can only be set on ordinary user accounts. If the target user's type is not ORDINARY — e.g. a service account or an AI account — the setPassword endpoint rejects the request. Service/AI accounts are not interactive-login accounts and must not hold local passwords.","triggerScenarios":"Calling POST /rest/v1/users/{userId}/password where the user's type is SERVICE or AI instead of ORDINARY.","commonSituations":"Scripts that iterate all users and try to set passwords on service accounts; mistaking a service account id for a normal user's; automation tooling that syncs credentials across all account types.","solutions":["Verify the target account's type is ORDINARY before calling the password endpoint","Remove service/AI accounts from bulk password-set operations","If credential-like access is needed for a service account, use access tokens instead of passwords"],"exampleFix":"// before\nawait rest.post(`/users/${svc.id}/password`, {password}); // 400: not ORDINARY\n// after\nif (svc.type === 'ORDINARY') {\n  await rest.post(`/users/${svc.id}/password`, {password});\n} else {\n  await rest.post(`/users/${svc.id}/tokens`, ...); // access token instead\n}","handlingStrategy":"validation","validationCode":"const user = await rest.get(`/users/${userId}`); if (user.type !== 'ORDINARY') throw new Error('Passwords can only be set on ordinary accounts');","typeGuard":"function isOrdinaryUser(user) { return user.type === 'ORDINARY'; }","tryCatchPattern":"try { await rest.post(`/users/${id}/password`, {password}); } catch (e) { if (e.status === 400 && /service or AI account/.test(e.message)) { /* use access tokens instead */ } else throw e; }","preventionTips":["Only target ORDINARY accounts in password scripts","Use access tokens for service/AI accounts instead of passwords","Verify account type before any credential mutation"],"tags":["rest-api","password","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"}