withastro/astro · error · AstroError
FontFileUrlNotFound
FontFileUrlNotFound
Error message
The `"${url}"` URL passed to the `experimental_getFontFileURL()` function is invalid. What it means
Part of the experimental Fonts API. `experimental_getFontFileURL(url, requestUrl?)` (packages/astro/src/assets/fonts/runtime.ts) can only resolve URLs that the fonts pipeline registered at build time; the underlying `runtimeFontFileUrlResolver.resolve()` returns null for anything else, which is rethrown as `FontFileUrlNotFound` with the failed resolution as `cause`.
Solutions
- Only pass URLs that come from the `fontData` object (keyed by CSS variable) exported by the experimental Fonts API — never hand-written paths.
- Confirm the family is actually present in your `fonts` configuration and builds without warnings, so its URLs get registered.
- Log the available entries of `fontData` once to see the exact URL keys the resolver knows about.
Example fix
// before — hand-written URL, never registered by the fonts pipeline
const url = experimental_getFontFileURL('/fonts/noto-regular.woff2');
// after — URL obtained from fontData
const { fonts } = fontData; // keyed by cssVariable
const url = experimental_getFontFileURL(fonts['--my-noto'].urls[0], Astro.url); Defensive patterns
Strategy: validation
Validate before calling
// only call the resolver with URLs the pipeline registered
const knownUrls: string[] = Object.values(fontData).flatMap((entry: any) =>
Object.values(entry.variants ?? {}).flatMap((v: any) => Object.values(v)),
).filter((u): u is string => typeof u === 'string');
if (!knownUrls.includes(candidateUrl)) {
throw new Error(`URL not registered by the fonts pipeline: ${candidateUrl}`);
} Type guard
const isRegisteredFontUrl = (url: string, fontData: Record<string, any>): boolean =>
Object.values(fontData).some((entry) =>
JSON.stringify(entry).includes(url),
); Try / catch
try {
const fileUrl = experimental_getFontFileURL(url, Astro.url);
} catch (err) {
if (err instanceof AstroError && err.name === 'FontFileUrlNotFound') {
// fall back to the family's primary URL or skip the font-dependent render
} else throw err;
} Prevention
- Derive every URL you pass from fontData; never concatenate paths by hand.
- Log Object.keys(fontData) once during onboarding to learn the registered keys.
- Keep the fonts config and the consuming components in the same PR so registrations stay in sync.
When it happens
Trigger: Calling `experimental_getFontFileURL()` with a hand-written path or a URL that was not obtained from the `fontData` object — e.g. `experimental_getFontFileURL('/fonts/my-font.woff2')` — or with a URL for a family that was not included in the `fonts` config.
Common situations: Experimenting with the experimental fonts API and guessing the URL shape; copy-pasting a font path from `dist/`; a family silently dropped from config so its URLs were never registered.
Related errors
- MissingGetFontFileRequestUrl
- CannotExtractFontType
- FontFamilyNotFound
- Server address unavailable, this should not happen. Open an…
- [astro:cache] Background revalidation failed for
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/f79bea38927df72a.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/assets/fonts/core/create-get-font-file-url.ts:13
import { AstroError, AstroErrorData } from '../../../core/errors/index.js';
import type { RuntimeFontFileUrlResolver } from '../definitions.js';
export function createGetFontFileURL(runtimeFontFileUrlResolver: RuntimeFontFileUrlResolver) {
return function getFontFileURL(url: string, requestUrl?: URL): string {
try {
const result = runtimeFontFileUrlResolver.resolve(url, requestUrl);
if (result === null) {
throw new Error('Not found');
}
return result;
} catch (cause) {
throw new AstroError(
{
...AstroErrorData.FontFileUrlNotFound,
message: AstroErrorData.FontFileUrlNotFound.message(url),
},
{ cause },
);
}
};
}
View on GitHub (pinned to 52e6c34790)