PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Writer\Exception
Line ending must be \n (Unix) or \r\n (Windows)
Error message
Line ending must be \n (Unix) or \r\n (Windows)
What it means
The HTML writer serializes output using a line-ending setting restricted to exactly two sequences: Unix LF and Windows CRLF. setLineEnding() enforces that whitelist and throws for anything else, including a lone CR, an empty string, or markup like '<br>'. The default is PHP_EOL, which is always one of the accepted values on every platform.
Solutions
- Pass one of the two allowed literals: LF or CRLF.
- Omit the call entirely; the default PHP_EOL is always accepted.
- Whitelist configuration before applying it: only accept the two exact sequences, otherwise fall back to PHP_EOL or reject the config.
Example fix
// before
$writer->setLineEnding('<br>'); // throws: only LF or CRLF allowed
// after
$writer->setLineEnding(chr(10)); // LF, Unix
$writer->setLineEnding(chr(13) . chr(10)); // CRLF, Windows
// or omit the call: the default PHP_EOL is always accepted Defensive patterns
Strategy: validation
Validate before calling
$eol = $config['line_ending'] ?? PHP_EOL;
$allowed = [chr(10), chr(13) . chr(10)]; // LF, CRLF
if (!in_array($eol, $allowed, true)) {
$eol = PHP_EOL; // or reject the configuration value
}
$writer->setLineEnding($eol); Prevention
- Whitelist newline settings to the two exact sequences before applying them.
- Rely on the default PHP_EOL unless a specific output format requires CRLF.
- Do not share EOL constant lists with CSV code, which permits a lone CR.
When it happens
Trigger: setLineEnding() with a lone carriage return, an empty string, '<br>', or PHP_EOL concatenated with extra characters; passing a user-configurable newline setting straight from an export configuration screen; reusing an EOL constant list meant for CSV, which also permits a third value.
Common situations: Export settings UIs exposing free-text newline fields; shared newline constants between CSV and HTML writers where the CSV-legal lone CR leaks into the HTML writer.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- Directory does not exist: $cacheDirectory
- Chart is not yet implemented
- Could not close file after writing.
- Could not open file " " for writing.
- Function $function() doesn't exist
AI-assisted analysis of PHPOffice/PhpSpreadsheet@65b080eef4 (2026-08-17).
Data as JSON: /api/errors/32d0b864f44d16ab.
Report an issue: GitHub.
Appendix: source
Thrown at src/PhpSpreadsheet/Writer/Html.php:92
*/
protected string $imagesRoot = '';
/**
* embed images, or link to images.
*/
protected bool $embedImages = false;
protected string $lineEnding = PHP_EOL;
public function getLineEnding(): string
{
return $this->lineEnding;
}
public function setLineEnding(string $lineEnding): self
{
if ($lineEnding != "\n" && $lineEnding !== "\r\n") {
throw new Exception('Line ending must be \n (Unix) or \r\n (Windows)');
}
$this->lineEnding = $lineEnding;
return $this;
}
protected bool $dataFormula = false;
public function setDataFormula(bool $dataFormula): self
{
$this->dataFormula = $dataFormula;
return $this;
}
protected bool $preserveFormatAndValue = false;
public function setPreserveFormatAndValue(bool $preserveFormatAndValue): selfView on GitHub (pinned to 65b080eef4)