PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Calculation\Exception
#VALUE!
Error message
#VALUE!
What it means
TextData\Format::convertValue() preprocesses the argument for VALUE() and NUMBERVALUE(). After trimming, if the string is itself an Excel error value ('#REF!', '#DIV/0!', ...), it rethrows CalcExp with that exact string, propagating the upstream error into the function's result. The reported '#VALUE!' message is the special case where the input string literally was '#VALUE!'.
Source
Thrown at src/PhpSpreadsheet/Calculation/TextData/Format.php:160
}
/**
* @param mixed $value Value to check
*/
private static function convertValue(mixed $value, bool $spacesMeanZero = false): mixed
{
$value = $value ?? 0;
if (is_bool($value)) {
if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) {
$value = (int) $value;
} else {
throw new CalcExp(ExcelError::VALUE());
}
}
if (is_string($value)) {
$value = trim($value);
if (ErrorValue::isError($value, true)) {
throw new CalcExp($value);
}
if ($spacesMeanZero && $value === '') {
$value = 0;
}
}
return $value;
}
/**
* VALUE.
*
* @param mixed $value Value to check
* Or can be an array of values
*
* @return array<mixed>|DateTimeInterface|float|int|string A string if arguments are invalid
* If an array of values is passed for the argument, then the returned result
* will also be an array with matching dimensionsView on GitHub (pinned to 65b080eef4)
Solutions
- Clean the source cell/region first: fix the upstream formula producing the error, or wrap it with IFERROR
- Pre-check in the formula: =IF(ISERROR(A1), "", VALUE(A1))
- Strip literal error strings in PHP before passing values in: if (ErrorValue::isError($v, true)) handle separately
- When calling Format::VALUE()/NUMBERVALUE() directly, catch Calculation\Exception and use its message as the error result
Example fix
// before: A1 holds #REF! -> VALUE propagates it
$sheet->getCell('B1')->setValue('=VALUE(A1)');
// after
$sheet->getCell('B1')->setValue('=IF(ISERROR(A1), "", VALUE(A1))'); Defensive patterns
Strategy: validation
Validate before calling
use PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue;
if (is_string($value) && ErrorValue::isError(trim($value), true)) {
return ''; // or propagate deliberately: return $value;
}
return Format::VALUE($value); Type guard
function isErrorString(mixed $v): bool
{
return is_string($v) && \PhpOffice\PhpSpreadsheet\Calculation\Information\ErrorValue::isError(trim($v), true);
} Try / catch
try {
$v = Format::VALUE($input);
} catch (\PhpOffice\PhpSpreadsheet\Calculation\Exception $e) {
$v = $e->getMessage(); // the propagated error string, e.g. '#REF!'
} Prevention
- Clear upstream errors (IFERROR/IFNA) before VALUE()/NUMBERVALUE() stages
- Sanitize imported text columns for literal '#...' strings
- Treat propagated error messages as data-quality signals, not as values to re-parse
When it happens
Trigger: =VALUE(A1) or =NUMBERVALUE(A1) where A1 contains or evaluates to an error value (for example a #VALUE! or #REF! produced by another formula); =VALUE("#N/A") with a literal error string; calling Format::VALUE('#VALUE!') directly, which throws Calculation\Exception instead of returning the string.
Common situations: Chained conversions where an earlier stage left error markers in text columns; imported files in which errors were saved as literal '#...' strings; ETL flows that try to normalize mixed columns with VALUE() and hit residue error text.
Related errors
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/8e2e931300b8a6a9.
Report an issue: GitHub.