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

  1. Only pass URLs that come from the `fontData` object (keyed by CSS variable) exported by the experimental Fonts API — never hand-written paths.
  2. Confirm the family is actually present in your `fonts` configuration and builds without warnings, so its URLs get registered.
  3. 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

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


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)