{"record":{"id":"31266a0f44bab128","repo":"apolloconfig/apollo","slug":"accesskey-should-disable-first","errorCode":null,"errorMessage":"AccessKey should disable first","messagePattern":"AccessKey should disable first","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AccessKeyService.java","lineNumber":92,"sourceCode":"\n    accessKey.setMode(entity.getMode());\n    accessKey.setEnabled(entity.isEnabled());\n    accessKey.setDataChangeLastModifiedBy(operator);\n    accessKeyRepository.save(accessKey);\n\n    auditService.audit(AccessKey.class.getSimpleName(), id, Audit.OP.UPDATE, operator);\n    return accessKey;\n  }\n\n  @Transactional\n  public void delete(String appId, long id, String operator) {\n    AccessKey accessKey = accessKeyRepository.findOneByAppIdAndId(appId, id);\n    if (accessKey == null) {\n      throw BadRequestException.accessKeyNotExists();\n    }\n\n    if (accessKey.isEnabled()) {\n      throw new BadRequestException(\"AccessKey should disable first\");\n    }\n\n    accessKey.setDeleted(Boolean.TRUE);\n    accessKey.setDataChangeLastModifiedBy(operator);\n    accessKeyRepository.save(accessKey);\n\n    auditService.audit(AccessKey.class.getSimpleName(), id, Audit.OP.DELETE, operator);\n  }\n}\n","sourceCodeStart":74,"sourceCodeEnd":102,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AccessKeyService.java#L74-L102","documentation":"A BadRequestException (HTTP 400) thrown from AccessKeyService.delete() when the access key being deleted is still enabled (accessKey.isEnabled() returns true). Apollo requires that an access key be disabled before it can be soft-deleted, preventing accidental removal of an active credential that clients are still using for authentication.","triggerScenarios":"DELETE access key call (AccessKeyService.delete) for a key whose enabled flag is true. The key must first be updated to enabled=false via AccessKeyService.update before delete will succeed.","commonSituations":"Attempting to delete a key in a single step without disabling it first; a cleanup script that skips the disable step; confusion between the update and delete lifecycle.","solutions":["First call update to set enabled=false on the access key, then call delete.","In automated workflows, always follow the sequence: update(disable) → verify no clients break → delete.","Check the enabled status before attempting deletion and branch accordingly."],"exampleFix":"// before: try to delete an enabled key\naccessKeyApi.delete(appId, keyId); // fails if enabled\n\n// after: disable first, then delete\nAccessKeyDTO update = new AccessKeyDTO();\nupdate.setId(keyId);\nupdate.setEnabled(false);\nupdate.setDataChangeLastModifiedBy(operator);\naccessKeyApi.update(appId, update);\n// ... wait for clients to stop using the key ...\naccessKeyApi.delete(appId, keyId); // now succeeds","handlingStrategy":"validation","validationCode":"// Disable the key before attempting deletion\nif (accessKey.isEnabled()) {\n    AccessKeyDTO update = new AccessKeyDTO();\n    update.setId(accessKey.getId());\n    update.setEnabled(false);\n    update.setDataChangeLastModifiedBy(operator);\n    accessKeyApi.update(appId, update);\n}\naccessKeyApi.delete(appId, accessKey.getId());","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always follow the disable-then-delete sequence for access keys.","Check the enabled flag before attempting deletion.","In automated workflows, add a delay between disable and delete to ensure clients have rotated."],"tags":["access-key","lifecycle","security","state-violation","bad-request","apollo-biz"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}