PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Calculation\Exception
#NUM!
#NUM!
Error message
#NUM!
What it means
#NUM! from the hexadecimal validator used by HEX2BIN, HEX2DEC and HEX2OCT. ConvertHex::validateHex() runs on the uppercased value and throws Calculation\Exception('#NUM!') when it contains any character outside [0-9A-F], matching Excel's behaviour for invalid hex numbers.
Source
Thrown at src/PhpSpreadsheet/Calculation/Engineering/ConvertHex.php:170
}
try {
$value = self::validateValue($value);
$value = self::validateHex($value);
$places = self::validatePlaces($places);
} catch (Exception $e) {
return $e->getMessage();
}
$decimal = self::toDecimal($value);
return ConvertDecimal::toOctal($decimal, $places);
}
protected static function validateHex(string $value): string
{
if (strlen($value) > preg_match_all('/[0123456789ABCDEF]/', $value)) {
throw new Exception(ExcelError::NAN());
}
return $value;
}
}
View on GitHub (pinned to 65b080eef4)
Solutions
- Strip prefixes and non-hex characters first: $hex = preg_replace('/^0x|^#/i', '', trim($v)).
- Validate with preg_match('/^[0-9A-F]+$/i', $v)) before calling HEX2* functions.
- Convert oversized hex in PHP with hexdec()/gmp instead of the Excel wrappers.
Example fix
// before
$dec = ConvertHex::toDecimal('0x1F'); // '#NUM!'
// after
$hex = strtoupper(preg_replace('/^(0x|#)/i', '', trim('0x1F'))); // '1F'
$dec = ConvertHex::toDecimal($hex); Defensive patterns
Strategy: validation
Validate before calling
$hex = strtoupper(preg_replace('/^(0x|#)/i', '', trim((string) $value)));
if (!preg_match('/^[0-9A-F]{1,}$/', $hex)) {
throw new \InvalidArgumentException('value contains non-hex characters');
}
$dec = ConvertHex::toDecimal($hex); Type guard
/** HEX2* input: hex digits only after stripping 0x/# prefixes. */
function isValidHexString(mixed $v): bool
{
return is_string($v) && preg_match('/^[0-9A-Fa-f]+$/', $v) === 1;
} Prevention
- Strip '0x' and '#' prefixes (colour codes!) before conversion.
- Case does not matter (input is uppercased) but separators, spaces and signs do.
- For >10-digit hex use hexdec()/GMP rather than the Excel wrappers.
When it happens
Trigger: =HEX2DEC("G1"), =HEX2DEC("0x1F") ('X' is invalid after uppercasing), =HEX2BIN("1F ") (trailing space); PHP calls ConvertHex::toDecimal('XYZ') or values with # color prefixes like '#FF' ('#' fails).
Common situations: Hex strings carrying '0x' or '#' prefixes from programming/design contexts; mixed-case is fine (value is uppercased first) but any separator, sign or whitespace is not; values pasted from colour pickers or GUID fragments.
Related errors
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/a387276b8fa6a611.
Report an issue: GitHub.