{"record":{"id":"ba282984ed294faa","repo":"symfony/http-kernel","slug":"the-tokens-argument-of-s-must-be-greater-than-0-d-given","errorCode":null,"errorMessage":"The \"$tokens\" argument of \"%s\" must be greater than 0, \"%d\" given.","messagePattern":"The \"\\$tokens\" argument of \"(.+?)\" must be greater than 0, \"(.+?)\" given\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Attribute/RateLimit.php","lineNumber":48,"sourceCode":"    /** @var string[] */\n    public readonly array $methods;\n\n    /**\n     * @param string                          $limiter       The configured limiter name\n     * @param string|Expression|\\Closure|null $key           A literal string key, an Expression, or a Closure (defaults to client IP + method + path)\n     * @param int                             $tokens        The number of tokens to consume\n     * @param string[]|string                 $methods       HTTP methods to rate limit; empty means all methods\n     * @param bool                            $exposeHeaders Whether this limiter's state may be exposed via the `X-RateLimit-*` response headers, opt-in\n     */\n    public function __construct(\n        public readonly string $limiter,\n        public readonly string|Expression|\\Closure|null $key = null,\n        public readonly int $tokens = 1,\n        array|string $methods = [],\n        public readonly bool $exposeHeaders = false,\n    ) {\n        if ($this->tokens < 1) {\n            throw new \\InvalidArgumentException(\\sprintf('The \"$tokens\" argument of \"%s\" must be greater than 0, \"%d\" given.', self::class, $this->tokens));\n        }\n\n        if (\\in_array('GET', $methods = array_map('strtoupper', (array) $methods), true)) {\n            $methods[] = 'HEAD';\n        }\n        $this->methods = $methods;\n    }\n}\n","sourceCodeStart":30,"sourceCodeEnd":57,"githubUrl":"https://github.com/symfony/http-kernel/blob/aa3a39d7286a62cdfea98f0e69c651a3da6e36cf/Attribute/RateLimit.php#L30-L57","documentation":"The #[RateLimit] attribute validates its tokens argument at construction; the limiter must consume at least 1 token, so values < 1 throw InvalidArgumentException immediately when the attribute is instantiated. This is fail-fast validation of the attribute's parameters.","triggerScenarios":"Declaring #[RateLimit(tokens: 0)] or a negative value, or passing a non-literal (e.g. from config) that evaluates to 0 when PHP resolves the attribute on the controller.","commonSituations":"Copying an attribute example and setting tokens: 0 to 'disable' limiting (should remove the attribute instead); computing tokens from an env/config value that defaults to 0; integer division yielding 0.","solutions":["Set tokens to at least 1","Remove the #[RateLimit] attribute if you meant to disable rate limiting","Validate any config/env-derived token count before wiring it (max(1, $tokens))","Check for arithmetic that can produce 0 (e.g. intdiv, floor)"],"exampleFix":"// before\n#[RateLimit(tokens: 0)]\npublic function index() {...}\n\n// after\n#[RateLimit(tokens: 1)]\npublic function index() {...}","handlingStrategy":"validation","validationCode":"// resolve tokens from config safely before wiring the attribute\n$tokens = max(1, (int) ($config['rate_limit_tokens'] ?? 1));","typeGuard":null,"tryCatchPattern":"try { $attr = new \\Symfony\\Component\\HttpKernel\\Attribute\\RateLimit(tokens: $tokens); } catch (\\InvalidArgumentException $e) { $attr = new \\Symfony\\Component\\HttpKernel\\Attribute\\RateLimit(tokens: 1); }","preventionTips":["Never set tokens: 0 to 'disable' limiting — remove the attribute instead","Clamp config-derived values with max(1, $tokens)","Add unit tests that instantiate attributes with production config values","Watch for integer division that can yield 0"],"tags":["rate-limiting","attributes","validation","configuration"],"backgroundTag":"value-out-of-range","analyzedSha":"aa3a39d7286a62cdfea98f0e69c651a3da6e36cf","analyzedAt":"2026-09-13T18:03:36.509Z","contentChangedAt":"2026-09-13T18:03:36.509Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}