{"record":{"id":"561b528ca6679771","repo":"mongodb/laravel-mongodb","slug":"lock-lottery-must-be-a-couple-of-integers-chance-total-where","errorCode":null,"errorMessage":"Lock lottery must be a couple of integers [$chance, $total] where $chance <= $total. Example [2, 100]","messagePattern":"Lock lottery must be a couple of integers \\[\\$chance, \\$total\\] where \\$chance <= \\$total\\. Example \\[2, 100\\]","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Cache/MongoLock.php","lineNumber":35,"sourceCode":"{\n    /**\n     * Create a new lock instance.\n     *\n     * @param Collection      $collection The MongoDB collection\n     * @param string          $name       Name of the lock\n     * @param int             $seconds    Time-to-live of the lock in seconds\n     * @param string|null     $owner      A unique string that identifies the owner. Random if not set\n     * @param array{int, int} $lottery    Probability [chance, total] of pruning expired cache items. Set to [0, 0] to disable\n     */\n    public function __construct(\n        private readonly Collection $collection,\n        string $name,\n        int $seconds,\n        ?string $owner = null,\n        private readonly array $lottery = [2, 100],\n    ) {\n        if (! is_numeric($this->lottery[0] ?? null) || ! is_numeric($this->lottery[1] ?? null) || $this->lottery[0] > $this->lottery[1]) {\n            throw new InvalidArgumentException('Lock lottery must be a couple of integers [$chance, $total] where $chance <= $total. Example [2, 100]');\n        }\n\n        parent::__construct($name, $seconds, $owner);\n    }\n\n    /**\n     * Attempt to acquire the lock.\n     */\n    #[Override]\n    public function acquire(): bool\n    {\n        // The lock can be acquired if: it doesn't exist, it has expired,\n        // or it is already owned by the same lock instance.\n        $isExpiredOrAlreadyOwned = [\n            '$or' => [\n                ['$lte' => ['$expires_at', $this->getUTCDateTime()]],\n                ['$eq' => ['$owner', ['$literal' => $this->owner]]],\n            ],","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/mongodb/laravel-mongodb/blob/0634653039468ceb0268a69192bdac64469ed043/src/Cache/MongoLock.php#L17-L53","documentation":"MongoLock's constructor validates the optional lottery array used for lock acquisition probabilistics. It must be a two-element array [$chance, $total] of numeric values where the first is <= the second. The library throws InvalidArgumentException in the constructor when the array is malformed, missing elements, or out of order.","triggerScenarios":"Passing a 'lottery' config option to the Mongo cache/lock manager with: a non-numeric element (e.g. ['a', 100]), only one element or none ([2] or []), or chance > total (e.g. [200, 100]). The lottery is read from the cache config when instantiating MongoLock in src/Cache/","commonSituations":"Typo in cache config where 'lottery' is set to a string or single int; copying Laravel database lock lottery config but inverting the values; user attempting to raise lock-obtainment odds by setting a chance larger than the total.","solutions":["Fix the 'lottery' value in config/cache.php (or wherever MongoLock is constructed) to a valid [chance, total] pair like [2, 100]","Ensure both elements are numeric (int or numeric string) and present","Ensure chance <= total","Remove the custom 'lottery' option entirely to use the default [2, 100]"],"exampleFix":"// before\n'lottery' => [200, 100],\n// after\n'lottery' => [2, 100],","handlingStrategy":"validation","validationCode":"$lottery = config('cache.stores.mongodb.lottery', [2, 100]);\nassert(is_array($lottery) && count($lottery) === 2 && is_numeric($lottery[0]) && is_numeric($lottery[1]) && $lottery[0] <= $lottery[1]);","typeGuard":"function isValidLottery(mixed $lottery): bool {\n    return is_array($lottery) && count($lottery) === 2\n        && is_numeric($lottery[0]) && is_numeric($lottery[1])\n        && $lottery[0] <= $lottery[1];\n}","tryCatchPattern":"try {\n    $lock = new MongoCacheRepository($store->lock($name, $seconds));\n} catch (InvalidArgumentException $e) {\n    Log::error('Invalid lock lottery config', ['message' => $e->getMessage()]);\n    $lottery = [2, 100]; // fall back to default\n}","preventionTips":["Keep the default [2, 100] unless you have a measured reason to change it","Validate the lottery pair in a config bootstrap or phpunit config test","Never build the lottery array from unvalidated user input"],"tags":["configuration","cache","locks"],"backgroundTag":"invalid-config-value","analyzedSha":"0634653039468ceb0268a69192bdac64469ed043","analyzedAt":"2026-09-15T02:56:37.067Z","contentChangedAt":"2026-09-15T02:56:37.067Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}