apolloconfig/apollo · error · BadRequestException

AccessKeys count limit exceeded

Error message

AccessKeys count limit exceeded

What it means

A BadRequestException (HTTP 400) thrown from AccessKeyService.create() when the number of existing access keys for an appId has reached the hardcoded limit ACCESSKEY_COUNT_LIMIT (5). Apollo caps the number of access keys per app to prevent unbounded key proliferation. The count includes soft-deleted keys that have not been physically removed if the count query counts all rows (the check uses accessKeyRepository.countByAppId before the new key is saved).

Source

Thrown at apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/AccessKeyService.java:51

  private static final int ACCESSKEY_COUNT_LIMIT = 5;

  private final AccessKeyRepository accessKeyRepository;
  private final AuditService auditService;

  public AccessKeyService(AccessKeyRepository accessKeyRepository, AuditService auditService) {
    this.accessKeyRepository = accessKeyRepository;
    this.auditService = auditService;
  }

  public List<AccessKey> findByAppId(String appId) {
    return accessKeyRepository.findByAppId(appId);
  }

  @Transactional
  public AccessKey create(String appId, AccessKey entity) {
    long count = accessKeyRepository.countByAppId(appId);
    if (count >= ACCESSKEY_COUNT_LIMIT) {
      throw new BadRequestException("AccessKeys count limit exceeded");
    }

    entity.setId(0L);
    entity.setAppId(appId);
    entity.setDataChangeLastModifiedBy(entity.getDataChangeCreatedBy());
    AccessKey accessKey = accessKeyRepository.save(entity);

    auditService.audit(AccessKey.class.getSimpleName(), accessKey.getId(), Audit.OP.INSERT,
        accessKey.getDataChangeCreatedBy());

    return accessKey;
  }

  @Transactional
  public AccessKey update(String appId, AccessKey entity) {
    long id = entity.getId();
    String operator = entity.getDataChangeLastModifiedBy();

View on GitHub (pinned to d95fc18d11)

Solutions

  1. Delete unused or disabled access keys to free up slots (must disable first, then delete — see error [10]).
  2. Audit existing keys via AccessKeyService.findByAppId(appId) and remove obsolete ones.
  3. If 5 keys are genuinely all in active use, reconsider the key management strategy or consolidate.
  4. Implement a key lifecycle policy: create new, rotate clients, disable old, delete old.

Example fix

// before: blindly create keys
accessKeyApi.create(appId, newKey);

// after: clean up old disabled keys before creating new ones
List<AccessKeyDTO> keys = accessKeyApi.findByAppId(appId);
for (AccessKeyDTO key : keys) {
    if (!key.isEnabled()) {
        accessKeyApi.delete(appId, key.getId()); // frees a slot
    }
}
accessKeyApi.create(appId, newKey); // now succeeds
Defensive patterns

Strategy: validation

Validate before calling

// Check current key count before creating
List<AccessKey> existing = accessKeyService.findByAppId(appId);
if (existing.size() >= 5) {
    // delete unused/disabled keys first
    existing.stream().filter(k -> !k.isEnabled()).forEach(k ->
        accessKeyService.delete(appId, k.getId(), operator));
}
accessKeyService.create(appId, newKey);

Prevention

When it happens

Trigger: POST to create a new AccessKey for an appId that already has 5 (or more) access keys. The count is taken before insert; if count >= 5, the create is rejected.

Common situations: Key rotation without deleting old keys; abandoned/disabled keys left in the system; a provisioning script that creates keys on each deployment without cleanup; testing that creates many keys without removing prior ones.

Related errors


AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14). Data as JSON: /api/errors/d3a0547dc1307585. Report an issue: GitHub.