BookStackApp/BookStack · error · PdfExportException

Failed to create required font data in {$expectedPath}, Ensu

Error message

Failed to create required font data in {$expectedPath}, Ensure all content in this location is writable by the web server

What it means

Thrown by renderUsingDomPdf in app/Exports/PdfGenerator.php when Dompdf's FontMetrics::setFontFamily() fails while registering user-provided custom fonts from storage/fonts/dompdf. The library wraps any exception from font registration into this PdfExportException pointing at the dompdf font directory. It almost always indicates the web-server user cannot write the .ufm/.fm font metric files into that directory (or the font files themselves are corrupt/unreadable).

Source

Thrown at app/Exports/PdfGenerator.php:72

        }

        return $wkhtmlBinaryPath ?: '';
    }

    protected function renderUsingDomPdf(string $html): string
    {
        $options = config('exports.dompdf');
        $domPdf = new Dompdf($options);
        $domPdf->setBasePath(base_path('public'));

        $fontMetrics = $domPdf->getFontMetrics();
        $userFontfamilies = $this->getUserDomPdfFontFamilies();
        foreach ($userFontfamilies as $fontFamily => $fonts) {
            try {
                $fontMetrics->setFontFamily($fontFamily, $fonts);
            } catch (\Exception $exception) {
                $expectedPath = storage_path('fonts/dompdf');
                throw new PdfExportException("Failed to create required font data in {$expectedPath}, Ensure all content in this location is writable by the web server");
            }
        }

        $domPdf->loadHTML($this->convertEntities($html));
        $domPdf->render();

        return (string) $domPdf->output();
    }

    /**
     * @return array<string, array<string, string>>
     */
    protected function getUserDomPdfFontFamilies(): array
    {
        $fontStore = storage_path('fonts/dompdf');
        if (!is_dir($fontStore)) {
            return [];
        }

View on GitHub (pinned to 18f8469a1c)

Solutions

  1. Make storage/fonts/dompdf (and everything under storage/) writable by the web server user: chown -R www-data:www-data storage/fonts && chmod -R u+rwX storage/fonts.
  2. Clear stale/corrupt font data: delete all generated .ufm files (and any broken uploads) in storage/fonts/dompdf so they are regenerated on next export.
  3. Verify the .ttf files in storage/fonts/dompdf are valid, readable fonts (re-upload them); a corrupt font makes setFontFamily throw even with correct permissions.
  4. If running in a container, ensure the storage volume is writable at runtime, or pre-generate font metrics at build time as the runtime user.
  5. As a workaround, temporarily remove the custom fonts (empty storage/fonts/dompdf) to confirm the error is font-related rather than a general dompdf failure.

Example fix

// before (shell, as root on server)
ls -l storage/fonts/dompdf  # owned by root, web server cannot write

// after
chown -R www-data:www-data storage/fonts
clearstatcache && rm -f storage/fonts/dompdf/*.ufm
Defensive patterns

Strategy: try-catch

Validate before calling

<?php
$fontDir = storage_path('fonts/dompdf');
$isReady = !is_dir($fontDir) || (
    is_dir($fontDir) && is_writable($fontDir)
    && collect(glob($fontDir . '/*.ttf'))->every(fn($f) => is_readable($f))
    // all .ufm files that exist must be writable too
    && collect(glob($fontDir . '/*.ufm'))->every(fn($f) => is_writable($f))
);

Try / catch

try {
    $pdf = $pdfGenerator->fromHtml($html);
} catch (\BookStack\Exceptions\PdfExportException $e) {
    if (str_contains($e->getMessage(), 'Failed to create required font data in')) {
        // fix storage/fonts/dompdf permissions or remove custom fonts, then retry once
        Log::warning('Dompdf font registration failed', ['error' => $e->getMessage()]);
    }
    throw $e;
}

Prevention

When it happens

Trigger: Calling fromHtml() with the dompdf engine active (no pdf_command configured, no wkhtml binary) while storage/fonts/dompdf contains .ttf files, and FontMetrics::setFontFamily() throws — typically because it cannot write font metric/cache files, or a previously generated .ufm is stale/corrupt from a different dompdf/FontLib version.

Common situations: Deployments where storage/fonts was created by root or a different user than PHP-FPM/www-data; read-only storage mounts (immutable containers, read-only volumes); SELinux/AppArmor blocking writes to storage; upgrading dompdf so cached font metrics become incompatible; a corrupted uploaded .ttf that FontLib cannot parse so the metric registration blows up.

Related errors


AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02). Data as JSON: /api/errors/97b199112f89d4df. Report an issue: GitHub.