{"record":{"id":"953d9dbad569f9bf","repo":"ramsey/uuid","slug":"value-must-be-a-signed-decimal-or-a-string-contain","errorCode":null,"errorMessage":"Value must be a signed decimal or a string containing only digits 0-9 and, optionally, a decimal point or sign (+ or -)","messagePattern":"Value must be a signed decimal or a string containing only digits 0-9 and, optionally, a decimal point or sign \\(\\+ or -\\)","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"src/Type/Decimal.php","lineNumber":44,"sourceCode":" *\n * This class exists for type-safety purposes, to ensure that decimals returned from ramsey/uuid methods as strings are\n * truly decimals and not some other kind of string.\n *\n * To support values as true decimals and not as floats or doubles, we store the decimals as strings.\n *\n * @immutable\n */\nfinal class Decimal implements NumberInterface\n{\n    private string $value;\n    private bool $isNegative;\n\n    public function __construct(float | int | string | self $value)\n    {\n        $value = (string) $value;\n\n        if (!is_numeric($value)) {\n            throw new InvalidArgumentException(\n                'Value must be a signed decimal or a string containing only '\n                . 'digits 0-9 and, optionally, a decimal point or sign (+ or -)'\n            );\n        }\n\n        // Remove the leading +-symbol.\n        if (str_starts_with($value, '+')) {\n            $value = substr($value, 1);\n        }\n\n        // For cases like `-0` or `-0.0000`, convert the value to `0`.\n        if (abs((float) $value) === 0.0) {\n            $value = '0';\n        }\n\n        if (str_starts_with($value, '-')) {\n            $this->isNegative = true;\n        } else {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/ramsey/uuid/blob/da5b521600a707d2dd097598464bd3090de850f5/src/Type/Decimal.php#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 ''.","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"],"exampleFix":"// before\n$amount = new Decimal('1.234,50'); // German locale formatting\n// InvalidArgumentException: Value must be a signed decimal or a string containing only digits 0-9...\n\n// after: normalize the formatted value first\n$normalized = str_replace(['.', ','], ['', '.'], '1.234,50');\n$amount = new Decimal($normalized); // '1234.50'\n\n// or simply pass an unformatted value\n$amount = new Decimal(1234.50);","handlingStrategy":"validation","validationCode":"// Run before constructing Decimal\n$normalized = str_replace([' ', ','], ['', ''], trim((string) $value));\nif ($normalized === '' || !is_numeric($normalized)) {\n    throw new \\InvalidArgumentException('Expected a decimal number, got: ' . $value);\n}","typeGuard":"function isDecimalString(string $value): bool\n{\n    return is_numeric($value);\n}","tryCatchPattern":"use Ramsey\\Uuid\\Exception\\InvalidArgumentException;\n\ntry {\n    $decimal = new Decimal($input);\n} catch (InvalidArgumentException $e) {\n    // reject the input at the boundary; do not silently default\n    throw new \\InvalidArgumentException('amount must be numeric', 0, $e);\n}","preventionTips":["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"],"tags":["php","ramsey-uuid","decimal","validation","locale","type-object"],"backgroundTag":"numeric-validation-failed","analyzedSha":"da5b521600a707d2dd097598464bd3090de850f5","analyzedAt":"2026-08-21T01:35:29.252Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}