santifer/career-ops · warning
⚠️ Font file not found, keeping original reference: fonts/$
Error message
⚠️ Font file not found, keeping original reference: fonts/${name} What it means
Graceful-degradation warning while inlining fonts for PDF rendering in generate-pdf.mjs: a CSS font reference matching fonts/<name> could not be read with ENOENT, so instead of embedding a data: URL the original 'fonts/<name>' reference is kept and Chromium falls back to system fonts. Non-ENOENT errors still propagate; only a genuinely missing file warns.
Source
Thrown at generate-pdf.mjs:1409
const fontPath = resolve(fontsDir, name);
const rel = relative(fontsDir, fontPath);
if (rel.startsWith('..') || isAbsolute(rel)) {
console.warn(`⚠️ Font reference escapes fonts/, keeping original reference: ${name}`);
continue;
}
if (_fontDataUrlCache.has(fontPath)) {
dataUrls.set(name, _fontDataUrlCache.get(fontPath));
continue;
}
try {
const buf = await readFile(fontPath);
const ext = name.slice(name.lastIndexOf('.') + 1).toLowerCase();
const dataUrl = `url('data:${MIME[ext] || 'application/octet-stream'};base64,${buf.toString('base64')}')`;
_fontDataUrlCache.set(fontPath, dataUrl);
dataUrls.set(name, dataUrl);
} catch (err) {
if (err?.code !== 'ENOENT') throw err;
console.warn(`⚠️ Font file not found, keeping original reference: fonts/${name}`);
}
}
return html.replace(FONT_REF, (match, _quote, name) => dataUrls.get(name) || match);
}
/**
* Render an HTML string to a PDF file via headless Chromium.
*
* Writes the HTML to a temporary file in the baseDir and loads it via
* page.goto() to give the page a file:// origin. This allows relative
* resources (images, fonts) to load — setContent() runs from about:blank
* and Chromium blocks file:// subresource loads from non-file origins.
*
* Local url('./fonts/...') references are inlined as data: URLs first so
* fonts also survive the ATS normalization pass (which may strip font refs).
*
* @param {string} html - Full HTML document to render.
* @param {string} outputPath - Absolute path to write the PDF to.View on GitHub (pinned to 60398d6549)
Solutions
- Put the missing font file at fonts/<name> relative to the render baseDir (exact name from the warning)
- Or remove/replace the @font-face reference in the template if the font is not needed
- Verify the PDF afterwards — layout metrics (page count, spacing) can shift under fallback fonts
Example fix
# before cp template-with-fonts.html my-cv.html && node generate-pdf.mjs my-cv.html # fonts/Inter.ttf absent # after mkdir -p fonts && cp ~/Downloads/Inter.ttf fonts/Inter.ttf && node generate-pdf.mjs my-cv.html
Defensive patterns
Strategy: fallback
Validate before calling
import { existsSync } from 'node:fs';
import { join } from 'node:path';
for (const name of fontNamesReferencedBy(html)) {
if (!existsSync(join(baseDir, 'fonts', name))) {
console.warn(`font missing, expect fallback metrics: fonts/${name}`);
}
} Type guard
function hasAllFonts(html, baseDir) {
const names = [...html.matchAll(FONT_REF)].map((m) => m[2]);
return names.every((n) => existsSync(join(baseDir, 'fonts', n)));
} Try / catch
// Already warn-and-fallback by design; callers should react to the warning:
if (!hasAllFonts(html, baseDir)) {
// either populate fonts/ or accept layout drift and re-check pageCount
console.warn('font fallback will be used; verify page count and spacing');
} Prevention
- Ship the exact font files referenced by your template in fonts/ (and commit or vendor them)
- After any template font change, sync fonts/ to match the @font-face names
- Review rendered PDF page count after this warning — fallback fonts change text metrics
When it happens
Trigger: Rendering a CV whose template references fonts/<name> while the fonts/ directory (resolved against baseDir) lacks that file — e.g. template updated to a new font family, fonts/ never populated, or rendering from a cwd/baseDir where fonts/ does not exist. _fontDataUrlCache means the miss is retried per process, not cached.
Common situations: Customized templates/cv-template.html referencing webfonts never downloaded; cloning without the (gitignored) fonts/ dir; renaming a font file but not the CSS; batch renders from a different baseDir than interactive ones.
Related errors
- Could not determine the rendered PDF page count (received ${
- ${message} (--strict-pages requested)
- Could not determine the rendered PDF page count from its pag
- Image failed to decode within 10s (unreadable or corrupt fil
- [fetch] Playwright error: ${e.message} — falling back to pla
AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20).
Data as JSON: /api/errors/5d258976956e2fe9.
Report an issue: GitHub.