withastro/astro · error · AstroError

CannotFetchFontFile

CannotFetchFontFile

Error message

An error occurred while fetching the font file from ${url}.

What it means

Thrown by CachedFontFetcher.fetch when retrieving a font file fails. The fetcher first tries to read an absolute path from disk via readFile; otherwise it issues an HTTP request. Any failure (non-2xx status, network error, filesystem read error, or an unreadable response body) is wrapped in an AstroError with code CannotFetchFontFile, preserving the original cause.

Source

Thrown at packages/astro/src/assets/fonts/infra/cached-font-fetcher.ts:47

		}
		const data = await cb();
		await storage.setItemRaw(key, data);
		return data;
	}

	async fetch({ id, url, init }: FontFileData): Promise<Buffer> {
		return await this.#cache(this.#storage, id, async () => {
			try {
				if (isAbsolute(url)) {
					return await this.#readFile(url);
				}
				const response = await this.#fetch(url, init ?? undefined);
				if (!response.ok) {
					throw new Error(`Response was not successful, received status code ${response.status}`);
				}
				return Buffer.from(await response.arrayBuffer());
			} catch (cause) {
				throw new AstroError(
					{
						...AstroErrorData.CannotFetchFontFile,
						message: AstroErrorData.CannotFetchFontFile.message(url),
					},
					{ cause },
				);
			}
		});
	}
}

View on GitHub (pinned to d081033d5f)

Solutions

  1. Check network egress from the build/host environment to the font source host (curl the exact url from the error).
  2. Verify the URL is correct and the font family/weight exists on the remote provider; a 404/403 will trigger this.
  3. If the URL is a local absolute path, confirm the file exists and is readable by the build process.
  4. Pass a custom init (RequestInit) with headers/proxy if behind a corporate proxy or needing a User-Agent.
  5. Inspect the `cause` on the thrown AstroError for the underlying fetch/filesystem error detail.

Example fix

// before
experimentalSvgFonts({ families: [{ name: 'My Font', weight: 999 }] })

// after - verify the exact URL resolves before building
const res = await fetch('https://fonts.gstatic.com/.../myfont.woff2');
if (!res.ok) throw new Error(`font ${res.status}`);
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the URL before fetching
import { isAbsolute } from 'node:path';
function isValidFontUrl(url: string): boolean {
  try {
    if (isAbsolute(url)) return true; // local path handled by fs
    const u = new URL(url);
    return u.protocol === 'http:' || u.protocol === 'https:';
  } catch { return false; }
}

Try / catch

try {
  const buf = await fontFetcher.fetch({ id, url });
} catch (e) {
  if (e instanceof AstroError && e.code === 'CannotFetchFontFile') {
    // inspect e.cause for the underlying fetch/fs error; retry with a fallback provider
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling fetch({ id, url, init }) where url is a remote URL that returns a non-OK status (response.ok is false), or the network call rejects, or url is an absolute filesystem path that readFileSync cannot open. Any exception thrown inside the try block (including a thrown Error for status codes) is caught and rethrown as CannotFetchFontFile with the offending url interpolated.

Common situations: A font provider URL is unreachable due to a corporate proxy, a typo'd family/weight URL, the font CDN returning 403/404, the build host lacking egress to fonts.googleapis.com / fonts.gstatic.com, or a local file path that does not exist or has wrong permissions during build.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/fd2db7da02a72fd8. Report an issue: GitHub.