{"record":{"id":"d4d5166a5dc7983c","repo":"paragonie/random_compat","slug":"random-int-min-must-be-an-integer","errorCode":null,"errorMessage":"random_int(): $min must be an integer","messagePattern":"random_int\\(\\): \\$min must be an integer","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/random_int.php","lineNumber":57,"sourceCode":"     * @return int\n     */\n    function random_int($min, $max)\n    {\n        /**\n         * Type and input logic checks\n         *\n         * If you pass it a float in the range (~PHP_INT_MAX, PHP_INT_MAX)\n         * (non-inclusive), it will sanely cast it to an int. If you it's equal to\n         * ~PHP_INT_MAX or PHP_INT_MAX, we let it fail as not an integer. Floats\n         * lose precision, so the <= and => operators might accidentally let a float\n         * through.\n         */\n\n        try {\n            /** @var int $min */\n            $min = RandomCompat_intval($min);\n        } catch (TypeError $ex) {\n            throw new TypeError(\n                'random_int(): $min must be an integer'\n            );\n        }\n\n        try {\n            /** @var int $max */\n            $max = RandomCompat_intval($max);\n        } catch (TypeError $ex) {\n            throw new TypeError(\n                'random_int(): $max must be an integer'\n            );\n        }\n\n        /**\n         * Now that we've verified our weak typing system has given us an integer,\n         * let's validate the logic then we can move forward with generating random\n         * integers along a given range.\n         */","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/paragonie/random_compat/blob/b5d188cc9d5e02f94d2c41da23093f1ef557c5b1/lib/random_int.php#L39-L75","documentation":"random_int() coerces its $min boundary with RandomCompat_intval(); when $min is not integer-representable (fractional float, non-numeric string, object, etc.) it throws this TypeError. The polyfill enforces PHP 7's integer typing for random_int() on PHP 5 hosts.","triggerScenarios":"Calling random_int('1', 10) or random_int(1.5, 10) — RandomCompat_intval($min) throws and lib/random_int.php:57 rethrows as TypeError. The unit tests (testBirthday, testDistribution, testCoverage, testOutput, testRandomRange) exercise this path with invalid types.","commonSituations":"Range bounds coming from unvalidated user input, JSON-decoded floats (JSON numbers decode as floats), or string values from database rows.","solutions":["Cast and validate bounds: pass (int) values after confirming they are whole numbers.","Validate user-supplied bounds with filter_var($v, FILTER_VALIDATE_INT).","When decoding JSON, cast numbers explicitly: (int) $decoded['min'].","Ensure callers of wrapper functions pass integer-typed parameters."],"exampleFix":"// before\n$roll = random_int($_POST['min'], 6);\n// after\n$min = filter_var($_POST['min'], FILTER_VALIDATE_INT);\nif ($min === false) {\n    throw new InvalidArgumentException('min must be an integer');\n}\n$roll = random_int($min, 6);","handlingStrategy":"type-guard","validationCode":"function isValidInt($v): bool {\n    return is_int($v) || (is_string($v) && ctype_digit($v));\n}","typeGuard":"function toIntOrNull($v): ?int {\n    if (is_int($v)) return $v;\n    if (is_float($v) && floor($v) === $v) return (int) $v;\n    if (is_string($v) && preg_match('/^-?\\d+$/', $v)) return (int) $v;\n    return null;\n}","tryCatchPattern":"try {\n    $n = random_int($min, $max);\n} catch (TypeError $e) {\n    throw new InvalidArgumentException('random_int() bounds must be integers', 0, $e);\n}","preventionTips":["Cast both bounds to int after validating, every call site.","Use filter_var(..., FILTER_VALIDATE_INT) for user input.","Normalize JSON-decoded numbers with (int) before use.","Add int type declarations in PHP 7+ wrapper functions."],"tags":["php","typeerror","argument-validation","randomness"],"backgroundTag":"type-mismatch","analyzedSha":"b5d188cc9d5e02f94d2c41da23093f1ef557c5b1","analyzedAt":"2026-09-13T16:12:09.755Z","contentChangedAt":"2026-09-13T16:12:09.755Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}