{"record":{"id":"37c8212ca44ff117","repo":"theonedev/onedev","slug":"at-least-one-email-address-should-be-present-for-a","errorCode":null,"errorMessage":"At least one email address should be present for a user","messagePattern":"At least one email address should be present for a user","errorType":"http","errorClass":"ExplicitException","httpStatus":400,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/EmailAddressResource.java","lineNumber":146,"sourceCode":"\t\temailAddressService.sendVerificationEmail(emailAddress);\n\t\t\n\t\treturn emailAddressId;\n\t}\n\t\n\t@Api(order=300)\n\t@Path(\"/{emailAddressId}\")\n\t@DELETE\n\tpublic Response deleteEmailAddress(@PathParam(\"emailAddressId\") Long emailAddressId) {\n\t\tvar emailAddress = emailAddressService.load(emailAddressId);\n\t\tif (!SecurityUtils.isAdministrator() && !emailAddress.getOwner().equals(getAuthUser())) \n\t\t\tthrow new UnauthorizedException();\n\t\t\n\t\tif (emailAddress.isPrimary() && emailAddress.getOwner().getPassword() == null) {\n\t\t\tthrow new ExplicitException(\"Cannot delete primary email address of \"\n\t\t\t\t\t+ \"externally authenticated user\");\n\t\t}\n\t\tif (emailAddress.getOwner().getEmailAddresses().size() == 1)\n\t\t\tthrow new ExplicitException(\"At least one email address should be present for a user\");\n\t\temailAddressService.delete(emailAddress);\n\n\t\tif (!getAuthUser().equals(emailAddress.getOwner())) \n\t\t\tauditService.audit(null, \"deleted email address \\\"\" + emailAddress.getValue() + \"\\\" from account \\\"\" + emailAddress.getOwner().getName() + \"\\\" via RESTful API\", null, null);\n\n\t\treturn Response.ok().build();\n\t}\n\t\n}\n","sourceCodeStart":128,"sourceCodeEnd":156,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/EmailAddressResource.java#L128-L156","documentation":"deleteEmailAddress requires every user to retain at least one email address, so deleting the user's last remaining address throws ExplicitException(\"At least one email address should be present for a user\"). This invariant keeps the account reachable for notifications, commits attribution and login-related flows.","triggerScenarios":"DELETE /~api/emailAddresses/{id} when emailAddress.getOwner().getEmailAddresses().size() == 1, i.e. the target is the user's only email address.","commonSituations":"Scripts iterating all addresses of a user and deleting each without checking remaining count; cleanup jobs that accidentally remove the sole address of a new account.","solutions":["Add a new email address (POST /~api/emailAddresses) before deleting the last one.","Skip addresses that are the user's last one in your cleanup script (check count > 1 first).","If the whole account should go away, deactivate/delete the user account instead of its addresses."],"exampleFix":"// before: delete blindly\naddresses.forEach(a -> client.deleteEmailAddresses(a.getId()));\n// after: keep at least one\nif (addresses.size() > 1)\n    addresses.forEach(a -> client.deleteEmailAddresses(a.getId()));","handlingStrategy":"validation","validationCode":"// only delete when the user keeps at least one address\nvar remaining = owner.getEmailAddresses().size();\nif (remaining <= 1) throw new IllegalStateException(\"refusing to delete last email address of \" + owner.getName());","typeGuard":null,"tryCatchPattern":"try { client.deleteEmailAddress(id); }\ncatch (ExplicitException e) { log.warn(\"Cannot remove last email address; add a replacement first\"); }","preventionTips":["Count the user's addresses before each delete in bulk scripts.","Add the replacement address before removing the old one.","Treat per-account invariants (min one address, primary constraints) as preconditions in your automation."],"tags":["rest-api","email","validation"],"backgroundTag":"invalid-state-transition","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"}