paragonie/random_compat · error · TypeError
RandomCompat_substr(): First argument should be a string
Error message
RandomCompat_substr(): First argument should be a string
What it means
RandomCompat_substr() is a binary-safe replacement for substr($str, $start, $length) used by random_compat internals. Its first parameter must be a binary string; when anything else (int, null, bool, array, object) is passed, the function throws TypeError immediately rather than relying on PHP's silent coercion, which would hide bugs in byte-level string slicing.
Solutions
- Check is_string($input) before calling, and handle the false/null error case of whatever produced the value.
- If the value is a Stringable object, call (string) $obj explicitly.
- Verify argument order — first argument is the string, second the int start offset.
- Prefer public API random_bytes()/random_int(); RandomCompat_* internals are not part of the supported surface.
Example fix
// before
$chunk = RandomCompat_substr($fileData, 0, 32); // $fileData = file_get_contents() returning false
// after
$fileData = file_get_contents($path);
if (!is_string($fileData)) {
throw new RuntimeException('Could not read file');
}
$chunk = RandomCompat_substr($fileData, 0, 32); Defensive patterns
Strategy: type-guard
Validate before calling
if (!is_string($binaryString)) {
throw new InvalidArgumentException(
'RandomCompat_substr first argument must be a string, got ' . gettype($binaryString)
);
}
$chunk = RandomCompat_substr($binaryString, $start, $length); Type guard
function canSubstring($value, $start, $length = null): bool {
return is_string($value) && is_int($start) && ($length === null || is_int($length));
}
if (canSubstring($input, 0, 16)) {
$chunk = RandomCompat_substr($input, 0, 16);
} Try / catch
try {
$chunk = RandomCompat_substr($input, $start, $length);
} catch (TypeError $e) {
throw new InvalidArgumentException('Invalid substr input: ' . $e->getMessage(), 0, $e);
} Prevention
- Handle false/null returns of data-producing functions before slicing.
- Check argument order: string first, int offset second, int length third.
- Cast Stringable objects to string explicitly.
- Declare strict_types=1 to catch coercion mistakes early.
When it happens
Trigger: Calling RandomCompat_substr($value, ...) where $value is not a string — e.g. passing the result of random_bytes() through a function that returned false on error, passing null from an uninitialized variable, or passing an integer that you intended as a length/offset by mistake (wrong argument order).
Common situations: Mishandled error returns: calling substr-style helpers on the result of a function that can return false/null (file reads, DB fetches). Swapped arguments: RandomCompat_substr($start, $string). Frameworks/HALs returning objects (e.g. Stringable wrappers) rather than raw strings. JSON decoding yielding numbers where strings were expected.
Understand the failure class
Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.
Related errors
- RandomCompat_substr(): Second argument should be an integer
- RandomCompat_substr(): Third argument should be an integer…
- random_bytes(): $bytes must be an integer
- random_bytes(): $bytes must be an integer
- random_int(): $min must be an integer
AI-assisted analysis of paragonie/random_compat@b5d188cc9d (2026-09-13).
Data as JSON: /api/errors/86192fa0cc5d5eea.
Report an issue: GitHub.
Appendix: source
Thrown at lib/byte_safe_strings.php:106
) {
/**
* substr() implementation that isn't brittle to mbstring.func_overload
*
* This version uses mb_substr() in '8bit' mode to treat strings as raw
* binary rather than UTF-8, ISO-8859-1, etc
*
* @param string $binary_string
* @param int $start
* @param int|null $length (optional)
*
* @throws TypeError
*
* @return string
*/
function RandomCompat_substr($binary_string, $start, $length = null)
{
if (!is_string($binary_string)) {
throw new TypeError(
'RandomCompat_substr(): First argument should be a string'
);
}
if (!is_int($start)) {
throw new TypeError(
'RandomCompat_substr(): Second argument should be an integer'
);
}
if ($length === null) {
/**
* mb_substr($str, 0, NULL, '8bit') returns an empty string on
* PHP 5.3, so we have to find the length ourselves.
*/
/** @var int $length */
$length = RandomCompat_strlen($binary_string) - $start;
} elseif (!is_int($length)) {View on GitHub (pinned to b5d188cc9d)