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

  1. Normalize the input before constructing: strip thousands separators and currency symbols, and convert the decimal separator to '.'
  2. Validate first with is_numeric($value) and reject/re-prompt non-numeric input at the boundary
  3. Pass native int/float or plain digit strings (e.g. '1234.50') instead of formatted strings
  4. 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

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


AI-assisted analysis of ramsey/uuid@da5b521600 (2026-08-21). Data as JSON: /api/errors/953d9dbad569f9bf. Report an issue: GitHub.