{"record":{"id":"a938eea5aa948c0b","repo":"apereo/cas","slug":"the-request-is-throttled-as-capacity-is-entirely-c","errorCode":null,"errorMessage":"The request is throttled as capacity is entirely consumed. Available tokens are [{}]","messagePattern":"The request is throttled as capacity is entirely consumed\\. Available tokens are \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-bucket4j-core/src/main/java/org/apereo/cas/bucket4j/consumer/DefaultBucketConsumer.java","lineNumber":56,"sourceCode":"            val canProceed = FunctionUtils.doAndHandle(() -> {\n                if (properties.isBlocking()) {\n                    LOGGER.debug(\"Attempting to consume a token for the authentication attempt\");\n                    return bucket.tryConsume(1, MAX_WAIT_NANOS, BlockingStrategy.PARKING);\n                }\n                return bucket.tryConsume(1);\n            }, e -> {\n                LoggingUtils.error(LOGGER, e);\n                Thread.currentThread().interrupt();\n                return false;\n            }).get();\n\n            val headers = new LinkedHashMap<String, String>();\n            val availableTokens = bucket.getAvailableTokens();\n            if (!canProceed) {\n                val probe = bucket.tryConsumeAndReturnRemaining(1);\n                val seconds = TimeUnit.NANOSECONDS.toSeconds(probe.getNanosToWaitForRefill());\n                headers.put(HEADER_NAME_X_RATE_LIMIT_RETRY_AFTER_SECONDS, Long.toString(seconds));\n                LOGGER.warn(\"The request is throttled as capacity is entirely consumed. Available tokens are [{}]\", availableTokens);\n                return BucketConsumptionResult.builder()\n                    .retryAfterSeconds(seconds)\n                    .tokensRemaining(availableTokens)\n                    .consumed(false).headers(headers).build();\n            }\n            headers.put(HEADER_NAME_X_RATE_LIMIT_REMAINING, Long.toString(availableTokens));\n            return BucketConsumptionResult.builder()\n                .tokensRemaining(availableTokens)\n                .consumed(true).headers(headers).build();\n        });\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":69,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-bucket4j-core/src/main/java/org/apereo/cas/bucket4j/consumer/DefaultBucketConsumer.java#L38-L69","documentation":"This WARN indicates the rate-limit bucket is exhausted: bucket.tryConsume returned false, so the request is throttled. CAS computes a Retry-After value from the bucket refill probe and returns a BucketConsumptionResult with consumed=false plus X-Rate-Limit headers.","triggerScenarios":"consume() is called when all tokens in the bucket are already consumed (canProceed is false); happens on every request once the allowed rate is exceeded within the refill window.","commonSituations":"Client retry storms or brute-force attempts exhausting the throttle budget; overly aggressive rate-limit configuration (small capacity, long refill period); shared buckets keyed too broadly (e.g. same key for all users behind one proxy IP).","solutions":["Tune capacity/refill settings (e.g. cas.authn.throttle capacity and refill duration) to match legitimate traffic.","Verify the bucket key granularity so distinct users/clients are not throttled collectively.","If the client is yours, add backoff honoring the returned retryAfterSeconds / X-Rate-Limit-Retry-After-Seconds header.","Check for abusive traffic sources and block them upstream."],"exampleFix":"// before\ncas.authn.throttle.capacity=10\ncas.authn.throttle.refill-duration=PT1H\n// after\ncas.authn.throttle.capacity=100\ncas.authn.throttle.refill-duration=PT1M","handlingStrategy":"retry","validationCode":"// client-side: check remaining tokens before next call\nconst remaining = Number(response.headers['x-rate-limit-remaining']);\nif (remaining === 0) await sleep(Number(response.headers['x-rate-limit-retry-after-seconds']) * 1000);","typeGuard":null,"tryCatchPattern":"BucketConsumptionResult r = bucketConsumer.consume(key);\nif (!r.isConsumed()) {\n  long wait = r.getRetryAfterSeconds();\n  Thread.sleep(TimeUnit.SECONDS.toMillis(wait));\n  r = bucketConsumer.consume(key);\n}","preventionTips":["Honor Retry-After / X-Rate-Limit-Retry-After-Seconds headers with exponential backoff.","Size bucket capacity to legitimate peak traffic, not average traffic.","Key buckets per user/client, not globally, to avoid cross-user throttling.","Alert on sustained throttling to detect brute-force or retry storms."],"tags":["bucket4j","rate-limiting","throttled"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}