withastro/astro · error · AstroError
CannotFetchFontFile
CannotFetchFontFile
Error message
An error occurred while fetching the font file from ${url}. What it means
The fonts pipeline fetches every configured font file at build time through `cached-font-fetcher.ts`: absolute paths are read from disk with `readFile`, everything else with `fetch`, and a non-OK status is converted to an error. Any failure (network error, 404/403, DNS/TLS issue, ENOENT on a local path) is wrapped as `CannotFetchFontFile` with the original error as `cause` (packages/astro/src/assets/fonts/infra/cached-font-fetcher.ts:47).
Solutions
- From the same machine/CI that builds, verify reachability: `curl -I <font-url>` and check for 200.
- For absolute local paths, confirm the file exists and is readable at build time (`fs.existsSync` + permissions).
- If the host blocks automated fetches, download the font into the repo and reference the local file instead.
- Configure the proxy env vars (HTTP_PROXY/HTTPS_PROXY) your CI requires for outbound requests.
Example fix
// astro.config.mjs — before (unreachable / hotlink-protected URL) url: 'https://fonts.example.com/files/my-font.woff2' // after — vendored local file url: './src/assets/fonts/my-font.woff2'
Defensive patterns
Strategy: retry
Validate before calling
// preflight every remote font before build (run in CI before astro build)
const results = await Promise.all(fontUrls.map(async (url) => {
try {
const res = await fetch(url, { method: 'HEAD' });
return { url, ok: res.ok, status: res.status };
} catch (e) {
return { url, ok: false, status: String(e) };
}
}));
const bad = results.filter((r) => !r.ok);
if (bad.length) throw new Error('Unreachable fonts: ' + JSON.stringify(bad, null, 2)); Try / catch
try {
await fontFetcher.fetch({ id, url });
} catch (err) {
if (err.name === 'CannotFetchFontFile') {
// transient network: wait and retry once; permanent (404): surface the URL and fail the build
} else throw err;
} Prevention
- Vendor critical fonts into the repo instead of fetching from CDNs at build time.
- Add a CI preflight that HEAD-checks every configured font URL.
- Pin font CDN URLs with stable, versioned paths to avoid link rot.
When it happens
Trigger: A `url` in the `fonts` config that points to an unreachable remote host, returns 403/404 (hotlink protection, expired signed URL), or an absolute filesystem path that does not exist / is not readable on the build machine.
Common situations: CI builds without network access or behind a proxy; font CDNs blocking non-browser user-agents; Google Fonts URLs with expired parameters; local paths that exist on the dev machine but not in the CI container.
Related errors
- UnknownFilesystemError
- UnknownFilesystemError
- CannotDetermineWeightAndStyleFromFontFile
- [astro:cache] Background revalidation failed for
- font family cannot be retrieved by the provider. Did you…
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/fd2db7da02a72fd8.
Report an issue: GitHub.
Appendix: 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 52e6c34790)