ramsey/uuid · error · InvalidArgumentException
Value must be a signed decimal or a string containing only d
Error message
Value must be a signed decimal or a string containing only digits 0-9 and, optionally, a decimal point or sign (+ or -)
What it means
Ramsey\Uuid\Type\Decimal is the library's immutable value object for decimal numbers (used by number/time converters and returned by some UUID accessors). Its constructor casts the input to string and requires is_numeric() to accept it; anything else throws Ramsey\Uuid\Exception\InvalidArgumentException. This rejects locale-formatted, unit-suffixed and arbitrary strings. Note the acceptance is broad: scientific notation like '1e5' passes, while '1,234.5' and '12.5 EUR' fail.
Source
Thrown at src/Type/Decimal.php:44
*
* This class exists for type-safety purposes, to ensure that decimals returned from ramsey/uuid methods as strings are
* truly decimals and not some other kind of string.
*
* To support values as true decimals and not as floats or doubles, we store the decimals as strings.
*
* @immutable
*/
final class Decimal implements NumberInterface
{
private string $value;
private bool $isNegative;
public function __construct(float | int | string | self $value)
{
$value = (string) $value;
if (!is_numeric($value)) {
throw new InvalidArgumentException(
'Value must be a signed decimal or a string containing only '
. 'digits 0-9 and, optionally, a decimal point or sign (+ or -)'
);
}
// Remove the leading +-symbol.
if (str_starts_with($value, '+')) {
$value = substr($value, 1);
}
// For cases like `-0` or `-0.0000`, convert the value to `0`.
if (abs((float) $value) === 0.0) {
$value = '0';
}
if (str_starts_with($value, '-')) {
$this->isNegative = true;
} else {View on GitHub (pinned to da5b521600)
Solutions
- Normalize the input before constructing: strip thousands separators and currency symbols, and convert the decimal separator to '.'
- Validate first with is_numeric($value) and reject/re-prompt non-numeric input at the boundary
- Pass native int/float or plain digit strings (e.g. '1234.50') instead of formatted strings
- For money or precision-sensitive values, keep values as strings from a dedicated money library and avoid float round-trips
Example fix
// before
$amount = new Decimal('1.234,50'); // German locale formatting
// InvalidArgumentException: Value must be a signed decimal or a string containing only digits 0-9...
// after: normalize the formatted value first
$normalized = str_replace(['.', ','], ['', '.'], '1.234,50');
$amount = new Decimal($normalized); // '1234.50'
// or simply pass an unformatted value
$amount = new Decimal(1234.50); Defensive patterns
Strategy: validation
Validate before calling
// Run before constructing Decimal
$normalized = str_replace([' ', ','], ['', ''], trim((string) $value));
if ($normalized === '' || !is_numeric($normalized)) {
throw new \InvalidArgumentException('Expected a decimal number, got: ' . $value);
} Type guard
function isDecimalString(string $value): bool
{
return is_numeric($value);
} Try / catch
use Ramsey\Uuid\Exception\InvalidArgumentException;
try {
$decimal = new Decimal($input);
} catch (InvalidArgumentException $e) {
// reject the input at the boundary; do not silently default
throw new \InvalidArgumentException('amount must be numeric', 0, $e);
} Prevention
- Validate with is_numeric() before constructing
- Normalize locale formatting (thousands separators, decimal commas) at the input boundary
- Pass native int/float or plain digit strings
- Keep money values in dedicated money objects; avoid formatted strings in storage
When it happens
Trigger: Constructing new Decimal('1,234.50') (thousands separator), new Decimal('12,5') (locale decimal comma), new Decimal('12.5 EUR'), new Decimal('') or new Decimal('abc'). Also passing a float or int cast from a non-numeric string, or untrusted request input fed straight into the constructor.
Common situations: Applications running under locales with comma decimal separators formatting numbers before storage; currency amounts with symbols or separators; empty strings from null-coalescing defaults; API payloads where the field is optional and arrives as ''.
Related errors
- Value must be a signed integer or a string containing only d
- Value must be a hexadecimal number
- Fields used to create a UuidV2 must represent a version 2 (D
- Fields used to create a UuidV3 must represent a version 3 (n
- Fields used to create a UuidV4 must represent a version 4 (r
AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21).
Data as JSON: /api/errors/953d9dbad569f9bf.
Report an issue: GitHub.