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
- 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.
- 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.
- 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.
- 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.
- 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
- Add storage/fonts/dompdf to your deployment permission script (chown www-data, u+rwX).
- After every font upload or dependency upgrade, delete stale *.ufm files so metrics regenerate.
- Validate uploaded fonts are real TTFs before accepting them into storage/fonts/dompdf.
- In containers, run as the same user that owns storage/ or pre-chown in the entrypoint.
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
- Failed to create required font data at $expectedUfm, Ensure
- PDF Export via command failed due to timeout at {$timeout} s
- PDF Export via command failed with exit code {$process->getE
- PDF Export via command failed, unable to read PDF output fil
- Unexpected type of key value provided
AI-assisted analysis of BookStackApp/BookStack@18f8469a1c (2026-09-02).
Data as JSON: /api/errors/97b199112f89d4df.
Report an issue: GitHub.