{"record":{"id":"92a90f4443a4eb14","repo":"paragonie/random_compat","slug":"expected-an-integer","errorCode":null,"errorMessage":"Expected an integer.","messagePattern":"Expected an integer\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/cast_to_int.php","lineNumber":71,"sourceCode":"            /** @psalm-suppress InvalidOperand */\n            $number += 0;\n        }\n        /** @var int|float $number */\n\n        if (\n            is_float($number)\n                &&\n            $number > ~PHP_INT_MAX\n                &&\n            $number < PHP_INT_MAX\n        ) {\n            $number = (int) $number;\n        }\n\n        if (is_int($number)) {\n            return (int) $number;\n        } elseif (!$fail_open) {\n            throw new TypeError(\n                'Expected an integer.'\n            );\n        }\n        return $number;\n    }\n}\n","sourceCodeStart":53,"sourceCodeEnd":78,"githubUrl":"https://github.com/paragonie/random_compat/blob/b5d188cc9d5e02f94d2c41da23093f1ef557c5b1/lib/cast_to_int.php#L53-L78","documentation":"RandomCompat_intval() is the library's strict integer coercion helper. After attempting casts (floats, numeric strings, objects with known representations), if the value still is not an int and $fail_open is false, it throws a TypeError('Expected an integer.'). It guards random_int() and internal callers against non-integer inputs.","triggerScenarios":"Calling random_int($min, $max) with arguments that cannot be losslessly interpreted as integers: non-numeric strings ('abc'), floats with fractional parts (1.5), true/false, arrays, null, or objects; also passing values exceeding the integer size limits that fail the strict conversion.","commonSituations":"Bounds sourced from user input ($_GET['min']), JSON-decoded values that are strings, database BIGINT columns returned as strings on PHP 5, or accidental use of a float constant like M_PI as a bound.","solutions":["Validate and cast bounds before the call: random_int((int) $min, (int) $max) — only after confirming the value is genuinely numeric.","Use is_int()/is_numeric() checks on inputs from HTTP/JSON sources and reject non-integers with a 400-style response.","If you intended float math, use a non-cryptographic function instead; random_int only accepts integers."],"exampleFix":"// before\n$n = random_int($_GET['min'], $_GET['max']);\n\n// after\n$min = filter_var($_GET['min'], FILTER_VALIDATE_INT);\n$max = filter_var($_GET['max'], FILTER_VALIDATE_INT);\nif ($min === false || $max === false) {\n    throw new InvalidArgumentException('min/max must be integers');\n}\n$n = random_int($min, $max);","handlingStrategy":"validation","validationCode":"// before calling random_int\n$min = filter_var($rawMin, FILTER_VALIDATE_INT);\n$max = filter_var($rawMax, FILTER_VALIDATE_INT);\nif ($min === false || $max === false || $min > $max) {\n    throw new InvalidArgumentException('Bounds must be integers with min <= max');\n}","typeGuard":"function asIntOrNull($value) {\n    if (is_int($value)) return $value;\n    if (is_string($value) && preg_match('/^-?\\d+$/', $value)) return (int) $value;\n    return null;\n}","tryCatchPattern":"try {\n    $n = random_int($min, $max);\n} catch (TypeError $e) {\n    // input was not an integer: reject the request, do not retry blindly\n    throw new InvalidArgumentException('random_int bounds must be integers', 0, $e);\n} catch (Exception $e) {\n    // entropy source failure — handle separately\n}","preventionTips":["Never pass superglobal values ($_GET/$_POST) directly to random_int","JSON-decode with options and validate numeric fields are ints before use","Keep min <= max and within PHP_INT range before the call"],"tags":["php","typeerror","integer-type","input-validation"],"backgroundTag":"invalid-argument-value","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"}