apereo/cas · warning

Unable to obtain a bucket for

Error message

Unable to obtain a bucket for [{}]

What it means

DefaultBucketConsumer.consume logs this warning when the underlying bucket4j BucketStore returns null for the given key, i.e. no rate-limit bucket could be created or retrieved. The consumption attempt is abandoned and a BucketConsumptionResult with consumed=false is returned, so the request is treated as not consuming a token.

Solutions

  1. Verify bucket4j rate-limit configuration (bucket capacity, refill rates) is fully defined in CAS properties.
  2. Check the BucketStore backing (in-memory vs distributed) is correctly wired and reachable.
  3. Inspect the key derivation: confirm the key passed to consume() is non-null and produced as expected.
  4. Enable DEBUG logging for org.apereo.cas.bucket4j to trace bucket creation.

Example fix

// before: no bucket config
cas.authn.throttle.bucket4j.enabled=true
// after
cas.authn.throttle.bucket4j.enabled=true
cas.authn.throttle.bucket4j.capacity=100
cas.authn.throttle.bucket4j.refill-duration=PT1M
Defensive patterns

Strategy: fallback

Validate before calling

// before consuming, ensure rate limiting is configured
if (!casProperties.getAuthn().getThrottle().getBucket4j().isEnabled()) {
  skipThrottle();
}
if (key == null || key.isBlank()) throw new IllegalArgumentException("bucket key required");

Try / catch

BucketConsumptionResult r = bucketConsumer.consume(key);
if (r == null || !r.isConsumed() && r.getTokensRemaining() < 0) {
  LOGGER.warn("Bucket store returned no bucket for [{}]; allowing request via fallback", key);
  return BucketConsumptionResult.builder().consumed(true).build();
}

Prevention

When it happens

Trigger: bucketStore.obtainBucket(key) returns null inside consume(); typically the configured bucket store cannot resolve/create a bucket for that key (store misconfiguration, empty/invalid bucket configuration, or an unsupported key).

Common situations: Rate-limiting misconfigured in cas.authn.throttle / bucket4j properties so no valid bucket definition exists; a distributed bucket store (Redis/Hazelcast) failing to materialize buckets; keys produced by a custom principal resolver not matching store expectations.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/4aa298d6d01776b0. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-bucket4j-core/src/main/java/org/apereo/cas/bucket4j/consumer/DefaultBucketConsumer.java:34

 *
 * @author Misagh Moayyed
 * @since 6.5.0
 */
@RequiredArgsConstructor
@Slf4j
public class DefaultBucketConsumer implements BucketConsumer {
    private final CasReentrantLock lock = new CasReentrantLock();

    private final BucketStore bucketStore;

    private final BaseBucket4jProperties properties;

    @Override
    public BucketConsumptionResult consume(final String key) {
        return lock.tryLock(() -> {
            val bucket = bucketStore.obtainBucket(key);
            if (bucket == null) {
                LOGGER.warn("Unable to obtain a bucket for [{}]", key);
                return BucketConsumptionResult.builder().consumed(false).build();
            }

            val canProceed = FunctionUtils.doAndHandle(() -> {
                if (properties.isBlocking()) {
                    LOGGER.debug("Attempting to consume a token for the authentication attempt");
                    return bucket.tryConsume(1, MAX_WAIT_NANOS, BlockingStrategy.PARKING);
                }
                return bucket.tryConsume(1);
            }, e -> {
                LoggingUtils.error(LOGGER, e);
                Thread.currentThread().interrupt();
                return false;
            }).get();

            val headers = new LinkedHashMap<String, String>();
            val availableTokens = bucket.getAvailableTokens();
            if (!canProceed) {

View on GitHub (pinned to e7288fc434)