PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Writer\Exception
No writer found for type $writerType
Error message
No writer found for type $writerType
What it means
IOFactory::createWriter() accepts either one of the registered short names ('Xls', 'Xlsx', 'Ods', 'Csv', 'Html', plus the PDF writers 'Tcpdf', 'Dompdf', 'Mpdf' and anything added via registerWriter()) or a full writer class-string. The lookup is case-sensitive: a string that is neither a registered value (a class name) nor a registered key throws immediately, before any file work starts.
Source
Thrown at src/PhpSpreadsheet/IOFactory.php:94
self::WRITER_ODS => Writer\Ods::class,
self::WRITER_CSV => Writer\Csv::class,
self::WRITER_HTML => Writer\Html::class,
'Tcpdf' => Writer\Pdf\Tcpdf::class,
'Dompdf' => Writer\Pdf\Dompdf::class,
'Mpdf' => Writer\Pdf\Mpdf::class,
];
}
/**
* Create Writer\IWriter.
*/
public static function createWriter(Spreadsheet $spreadsheet, string $writerType): IWriter
{
/** @var class-string<IWriter> */
$className = $writerType;
if (!in_array($writerType, self::$writers, true)) {
if (!isset(self::$writers[$writerType])) {
throw new Writer\Exception("No writer found for type $writerType");
}
// Instantiate writer
$className = self::$writers[$writerType];
}
return new $className($spreadsheet);
}
/**
* Create IReader.
*
* @param array<string, class-string<IReader>> $mergeArray
* Array to use to find reader, self::$readers will be used if $readers is empty.
*/
public static function createReader(string $readerType, array $mergeArray = []): IReader
{
/** @var class-string<IReader> */View on GitHub (pinned to 65b080eef4)
Solutions
- Use the exact constants: IOFactory::WRITER_XLSX ('Xlsx'), WRITER_XLS ('Xls'), WRITER_CSV ('Csv'), WRITER_HTML ('Html'), WRITER_ODS ('Ods')
- Map PHPExcel-era names: 'Excel2007' -> 'Xlsx', 'Excel5' -> 'Xls', 'OOCalc' -> 'Ods'
- Normalize extension-derived strings with ucfirst() before passing, or pass a class-string like \PhpOffice\PhpSpreadsheet\Writer\Xlsx::class
Example fix
// before $type = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); // 'xlsx' $writer = IOFactory::createWriter($spreadsheet, $type); // after $type = ucfirst(strtolower(pathinfo($filename, PATHINFO_EXTENSION))); $writer = IOFactory::createWriter($spreadsheet, $type); // 'Xlsx'
Defensive patterns
Strategy: validation
Validate before calling
const KNOWN_WRITERS = ['Xls', 'Xlsx', 'Ods', 'Csv', 'Html', 'Tcpdf', 'Dompdf', 'Mpdf'];
/** Accept user input, extension, or PHPExcel-era names; return a valid writer type. */
function normalizeWriterType(string $type): string
{
$aliases = [
'excel2007' => 'Xlsx', 'excel5' => 'Xls', 'oocalc' => 'Ods',
'excel' => 'Xlsx', 'pdf' => 'Mpdf',
];
$type = $aliases[strtolower(trim($type))] ?? ucfirst(strtolower(trim($type)));
if (!in_array($type, KNOWN_WRITERS, true)
&& !is_a($type, \PhpOffice\PhpSpreadsheet\Writer\IWriter::class, true)) {
throw new InvalidArgumentException("Unknown writer type: $type");
}
return $type;
}
$writer = IOFactory::createWriter($spreadsheet, normalizeWriterType($userType)); Prevention
- Pass IOFactory constants (IOFactory::WRITER_XLSX etc.) instead of string literals
- When deriving from a file extension, normalize with ucfirst(strtolower(...)) first
- Add a mapping table for legacy PHPExcel names when migrating old codebases
When it happens
Trigger: IOFactory::createWriter($spreadsheet, 'xlsx') with lowercase; 'Excel2007'/'Excel5' (pre-1.0 PHPExcel names); any typo or stray whitespace like 'Xlsx '.
Common situations: Deriving the writer type from pathinfo() extension and passing it unnormalized; following old PHPExcel tutorials; case differences introduced during refactors.
Related errors
- No reader found for type $readerType
- Registered writers must implement PhpOffice\PhpSpreadsheet\W
- Directory does not exist: $cacheDirectory
- Could not open file "{$filename}" for writing.
- Could not close file after writing.
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/919d10d8849c8e13.
Report an issue: GitHub.