{"record":{"id":"f8999531e08a7815","repo":"PHPOffice/PhpSpreadsheet","slug":"function-function-doesn-t-exist","errorCode":null,"errorMessage":"Function $function() doesn't exist","messagePattern":"Function \\$function\\(\\) doesn't exist","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Writer\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Writer/Xls/Parser.php","lineNumber":1546,"sourceCode":"        $this->advance();\n        $this->advance(); // eat the \"(\"\n        while ($this->currentToken !== ')') {\n            if ($num_args > 0) {\n                if ($this->currentToken === ',' || $this->currentToken === ';') {\n                    $this->advance(); // eat the \",\" or \";\"\n                } else {\n                    throw new WriterException(\"Syntax error: comma expected in function $function, arg #{$num_args}\");\n                }\n                $result2 = $this->condition();\n                $result = $this->createTree('arg', $result, $result2);\n            } else { // first argument\n                $result2 = $this->condition();\n                $result = $this->createTree('arg', '', $result2);\n            }\n            ++$num_args;\n        }\n        if (!isset($this->functions[$function])) {\n            throw new WriterException(\"Function $function() doesn't exist\");\n        }\n        $args = $this->functions[$function][1];\n        // If fixed number of args eg. TIME($i, $j, $k). Check that the number of args is valid.\n        if (($args >= 0) && ($args != $num_args)) {\n            throw new WriterException(\"Incorrect number of arguments in function $function() \");\n        }\n\n        $result = $this->createTree($function, $result, $num_args);\n        $this->advance(); // eat the \")\"\n\n        return $result;\n    }\n\n    /**\n     * Creates a tree. In fact an array which may have one or two arrays (sub-trees)\n     * as elements.\n     *\n     * @param mixed $value the value of this node","sourceCodeStart":1528,"sourceCodeEnd":1564,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Writer/Xls/Parser.php#L1528-L1564","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Replace the unsupported function with an Excel 97-era equivalent (XLOOKUP -> VLOOKUP/INDEX+MATCH, TEXTJOIN -> CONCATENATE)","Write Xlsx instead of Xls if the consumer can accept it","Precompute the result in PHP and write the value instead of the formula","Catch WriterException at save and surface the reported function name to the caller"],"exampleFix":"// before\n$sheet->setCellValue('B2', '=XLOOKUP($A2,$D:$E,2,FALSE)');\n\n// after\n$sheet->setCellValue('B2', '=VLOOKUP($A2,$D:$E,2,FALSE)');","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    IOFactory::createWriter($spreadsheet, 'Xls')->save($path);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Writer\\Exception $e) {\n    if (preg_match('/Function (\\w+)\\(\\) doesn\\'t exist/u', $e->getMessage(), $m)) {\n        // $m[1] is the unsupported function, e.g. XLOOKUP\n        // fall back: write values instead of formulas, or use Xlsx\n        $spreadsheet->getCalculationEngine()?->disableEvaluation();\n    }\n}","preventionTips":["When exporting .xls, restrict formulas to the Excel 97 function set (no XLOOKUP, TEXTJOIN, IFS, LET, LAMBDA)","Keep a project-level allowlist of functions permitted in .xls exports and validate cell formulas against it","If modern functions are required, export Xlsx and convert with an external tool for legacy consumers"],"tags":["phpspreadsheet","xls","formula","unsupported-function","writer"],"backgroundTag":"unsupported-function","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}