PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Writer\Exception

Function $function() doesn't exist

Error message

Function $function() doesn't exist

What it means

The Xls writer can only emit functions present in Parser's internal $functions table (roughly the Excel 97/BIFF8 function set). After parsing a function call's argument list, if the uppercased function name is not in that table, the save aborts with this exception. Assigning the formula to the cell never fails - only IOFactory::createWriter($ss, 'Xls')->save() does.

Source

Thrown at src/PhpSpreadsheet/Writer/Xls/Parser.php:1546

        $this->advance();
        $this->advance(); // eat the "("
        while ($this->currentToken !== ')') {
            if ($num_args > 0) {
                if ($this->currentToken === ',' || $this->currentToken === ';') {
                    $this->advance(); // eat the "," or ";"
                } else {
                    throw new WriterException("Syntax error: comma expected in function $function, arg #{$num_args}");
                }
                $result2 = $this->condition();
                $result = $this->createTree('arg', $result, $result2);
            } else { // first argument
                $result2 = $this->condition();
                $result = $this->createTree('arg', '', $result2);
            }
            ++$num_args;
        }
        if (!isset($this->functions[$function])) {
            throw new WriterException("Function $function() doesn't exist");
        }
        $args = $this->functions[$function][1];
        // If fixed number of args eg. TIME($i, $j, $k). Check that the number of args is valid.
        if (($args >= 0) && ($args != $num_args)) {
            throw new WriterException("Incorrect number of arguments in function $function() ");
        }

        $result = $this->createTree($function, $result, $num_args);
        $this->advance(); // eat the ")"

        return $result;
    }

    /**
     * Creates a tree. In fact an array which may have one or two arrays (sub-trees)
     * as elements.
     *
     * @param mixed $value the value of this node

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Replace the unsupported function with an Excel 97-era equivalent (XLOOKUP -> VLOOKUP/INDEX+MATCH, TEXTJOIN -> CONCATENATE)
  2. Write Xlsx instead of Xls if the consumer can accept it
  3. Precompute the result in PHP and write the value instead of the formula
  4. Catch WriterException at save and surface the reported function name to the caller

Example fix

// before
$sheet->setCellValue('B2', '=XLOOKUP($A2,$D:$E,2,FALSE)');

// after
$sheet->setCellValue('B2', '=VLOOKUP($A2,$D:$E,2,FALSE)');
Defensive patterns

Strategy: try-catch

Try / catch

try {
    IOFactory::createWriter($spreadsheet, 'Xls')->save($path);
} catch (\PhpOffice\PhpSpreadsheet\Writer\Exception $e) {
    if (preg_match('/Function (\w+)\(\) doesn\'t exist/u', $e->getMessage(), $m)) {
        // $m[1] is the unsupported function, e.g. XLOOKUP
        // fall back: write values instead of formulas, or use Xlsx
        $spreadsheet->getCalculationEngine()?->disableEvaluation();
    }
}

Prevention

When it happens

Trigger: Saving to .xls a workbook whose formulas call functions outside the BIFF8 set, e.g. '=XLOOKUP(...)', '=TEXTJOIN(...)', '=IFS(...)', or a custom function registered with the Calculation engine.

Common situations: Code originally targeting Xlsx switched to Xls for a legacy downstream consumer; use of modern Excel functions in a project that must export .xls; user-entered formulas containing newer functions.

Related errors


AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17). Data as JSON: /api/errors/f8999531e08a7815. Report an issue: GitHub.