{"record":{"id":"afd0c05bf04c99bd","repo":"alibaba/Sentinel","slug":"intervalmillis-should-be-at-least-1000-but-given","errorCode":null,"errorMessage":"intervalMillis should be at least 1000, but given: ","messagePattern":"intervalMillis should be at least 1000, but given: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/TokenBucket.java","lineNumber":35,"sourceCode":"\nimport java.util.concurrent.atomic.AtomicLong;\n\nclass TokenBucket {\n\n    private final long maxTokens;\n\n    private final long intervalMillis;\n\n    private volatile long nextUpdate;\n\n    private AtomicLong tokens;\n\n    public TokenBucket(long maxTokens, long intervalMillis) {\n        if (maxTokens <= 0) {\n            throw new IllegalArgumentException(\"maxTokens should > 0, but given: \" + maxTokens);\n        }\n        if (intervalMillis < 1000) {\n            throw new IllegalArgumentException(\"intervalMillis should be at least 1000, but given: \" + intervalMillis);\n        }\n        this.maxTokens = maxTokens;\n        this.intervalMillis = intervalMillis;\n        this.nextUpdate = System.currentTimeMillis() / 1000 * 1000 + intervalMillis;\n        this.tokens = new AtomicLong(maxTokens);\n    }\n\n    public boolean accept(long now) {\n        long currTokens;\n        if (now > nextUpdate) {\n            currTokens = tokens.get();\n            if (tokens.compareAndSet(currTokens, maxTokens)) {\n                nextUpdate = System.currentTimeMillis() / 1000 * 1000 + intervalMillis;\n            }\n        }\n\n        do {\n            currTokens = tokens.get();","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/alibaba/Sentinel/blob/a3f40ba8e900c8489bd520274739f17235a7721c/sentinel-core/src/main/java/com/alibaba/csp/sentinel/eagleeye/TokenBucket.java#L17-L53","documentation":"TokenBucket requires intervalMillis >= 1000 (1 second). The refill logic resets tokens only when now > nextUpdate, so sub-second intervals would break the second-aligned update math (nextUpdate is computed as currentTimeMillis / 1000 * 1000 + intervalMillis). Anything below 1000ms is rejected with IllegalArgumentException.","triggerScenarios":"new TokenBucket(maxTokens, intervalMillis) with intervalMillis < 1000, e.g. new TokenBucket(10, 500) or passing seconds instead of milliseconds via a typo'd constant.","commonSituations":"Confusing units (passing 1 meaning 1 second instead of 1000ms), or copying a sub-second refresh interval from another rate limiter's config into EagleEye's TokenBucket.","solutions":["Pass an interval of at least 1000 milliseconds, e.g. 1000 or 60000.","Verify the unit of the value feeding intervalMillis; convert seconds to milliseconds if needed.","If sub-second granularity is required, TokenBucket cannot support it — use a different rate-limiting utility."],"exampleFix":"// before\nnew TokenBucket(10, 500); // wanted 500ms\n\n// after\nnew TokenBucket(10, 1000); // minimum supported interval","handlingStrategy":"validation","validationCode":"long interval = requestedIntervalMs < 1000 ? 1000 : requestedIntervalMs; // clamp or reject\nif (requestedIntervalMs < 1000) {\n    throw new ConfigurationException(\"interval must be >= 1000ms\");\n}\nTokenBucket bucket = new TokenBucket(maxTokens, interval);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Name variables with explicit units (intervalMillis not interval) to avoid seconds/ms mix-ups.","Document that EagleEye TokenBucket granularity is seconds; do not port sub-second configs from other limiters."],"tags":["sentinel","eagleeye","rate-limit","units","constructor-validation"],"backgroundTag":null,"analyzedSha":"a3f40ba8e900c8489bd520274739f17235a7721c","analyzedAt":"2026-08-14T11:10:30.678Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}