remotion-dev/remotion · error

Failed to load font

Error message

Failed to load font ${JSON.stringify(fontUrl)}: ${response.status} ${response.statusText}

What it means

Remotion fetches @font-face font files at composition time so they can be embedded during rendering. If the HTTP response for the font URL is not ok (e.g. 404, 403, 500), fetchFontData throws with the URL and status. Rendering fails fast rather than silently falling back to a missing font.

Solutions

  1. Verify the font URL returns 200 (curl -I the URL).
  2. Fix or re-upload the font asset / regenerate presigned URLs.
  3. Use a local font file path or hosted URL that is reachable from the render environment.
  4. Check network/firewall and CORS settings in the rendering environment.

Example fix

// before
await loadFont({family: 'X', url: 'https://cdn.example.com/old-font.woff2'})
// after
await loadFont({family: 'X', url: 'https://cdn.example.com/font-v2.woff2'}) // verified 200
Defensive patterns

Strategy: retry

Validate before calling

const res = await fetch(fontUrl, {method: 'HEAD'});
if (!res.ok) throw new Error(`Font unavailable: ${res.status}`);

Try / catch

try {
  await loadFont({family, url: fontUrl});
} catch (e) {
  if (String(e).includes('Failed to load font')) {
    await loadFont({family, url: fallbackFontUrl});
  }
}

Prevention

When it happens

Trigger: Loading a font via loadFont/FontFace with a URL that returns a non-2xx status; expired signed URLs; CORS-proxied or blocked font hosts returning error pages.

Common situations: Typo'd font URL; font removed from CDN; S3/GCS presigned URL expired; local dev server not running when rendering; network restrictions in Lambda/CI.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of remotion-dev/remotion@46a3a6bf13 (2026-09-18). Data as JSON: /api/errors/c8eaf09a8cf3c630. Report an issue: GitHub.

Appendix: source

Thrown at packages/core/src/font-face-registry.ts:30

	weight: string | null;
	stretch: string | null;
	unicodeRange: string | null;
	variant: string | null;
};

const registeredFontFaces: RegisteredFontFace[] = [];
const fontDataByUrl = new Map<string, Promise<ArrayBuffer>>();

export const fetchFontData = (fontUrl: string): Promise<ArrayBuffer> => {
	const cached = fontDataByUrl.get(fontUrl);
	if (cached) {
		return cached;
	}

	const promise = fetch(fontUrl)
		.then((response) => {
			if (!response.ok) {
				throw new Error(
					`Failed to load font ${JSON.stringify(fontUrl)}: ${response.status} ${response.statusText}`,
				);
			}

			return response.arrayBuffer();
		})
		.catch((error) => {
			fontDataByUrl.delete(fontUrl);
			throw error;
		});

	fontDataByUrl.set(fontUrl, promise);
	return promise;
};

export const registerFontFace = (fontFace: RegisteredFontFace) => {
	if (
		registeredFontFaces.some(

View on GitHub (pinned to 46a3a6bf13)