PHPOffice/PhpSpreadsheet · error · PhpOffice\PhpSpreadsheet\Exception

unexpected null font

Error message

unexpected null font

What it means

RichText\Run::getFontOrThrow() returns the run's Font or throws when it is null. The constructor always assigns a default Font (src/PhpSpreadsheet/RichText/Run.php:24), so null can only appear after setFont(null) — setFont accepts ?Font — or in a subclass that bypasses the constructor. The OrThrow variant exists so code that genuinely requires a font (writers, renderers) can fail loudly instead of silently mishandling null.

Source

Thrown at src/PhpSpreadsheet/RichText/Run.php:38

    public function __construct(string $text = '')
    {
        parent::__construct($text);
        // Initialise variables
        $this->font = new Font();
    }

    /**
     * Get font.
     */
    public function getFont(): ?Font
    {
        return $this->font;
    }

    public function getFontOrThrow(): Font
    {
        if ($this->font === null) {
            throw new SpreadsheetException('unexpected null font');
        }

        return $this->font;
    }

    /**
     * Set font.
     *
     * @param ?Font $font Font
     *
     * @return $this
     */
    public function setFont(?Font $font = null): static
    {
        $this->font = $font;

        return $this;
    }

View on GitHub (pinned to 65b080eef4)

Solutions

  1. Use the nullable accessor with a fallback: $run->getFont() ?? new Font()
  2. Stop calling setFont(null); keep the default font or explicitly set a Font instance
  3. If a run's font was nulled by upstream code, re-create the Run (its constructor installs a default Font)

Example fix

// before
$run->setFont(null);
$font = $run->getFontOrThrow(); // throws: unexpected null font

// after
$font = $run->getFont() ?? new \PhpOffice\PhpSpreadsheet\Style\Font();
Defensive patterns

Strategy: type-guard

Validate before calling

$run = new \PhpOffice\PhpSpreadsheet\RichText\Run('text');
$run->setFont(null); // if this must stay, use getFont() downstream

Type guard

function runHasFont(\PhpOffice\PhpSpreadsheet\RichText\Run $run): bool
{
    return $run->getFont() !== null;
}

// usage
$font = $run->getFont() ?? new \PhpOffice\PhpSpreadsheet\Style\Font();

Try / catch

try {
    $font = $run->getFontOrThrow();
} catch (\PhpOffice\PhpSpreadsheet\Exception $e) {
    $font = new \PhpOffice\PhpSpreadsheet\Style\Font(); // sensible default
}

Prevention

When it happens

Trigger: Creating a Run, calling setFont(null) (often to mimic inheritance from the cell font), then calling getFontOrThrow(); assembling rich text via setRichTextElements() with hand-built runs whose fonts were nulled; passing such a Run to export code that calls getFontOrThrow().

Common situations: Code that nulls run fonts to 'inherit' the base font before export, then hits a writer needing a concrete font; refactors from getFont() (nullable tolerated) to getFontOrThrow(); partial deserialization of rich text from JSON.


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