withastro/astro · error · AstroError
CannotExtractFontType
CannotExtractFontType
Error message
An error occurred while trying to extract the font type from ${url}. What it means
The fonts pipeline determines each font's type purely from the URL's file extension via `extname(url).slice(1)` and validates it against the supported set (`woff2`, `woff`, `otf`, `ttf`, `eot` — packages/astro/src/assets/fonts/constants.ts:27). An extension that is missing or not in that set throws `CannotExtractFontType` (packages/astro/src/assets/fonts/infra/node-font-type-extractor.ts:11).
Solutions
- Point `url` at a file or URL whose extension is one of: woff2, woff, otf, ttf, eot (a query string after the extension is fine: `font.woff2?v=2` works, `font?v=2` does not).
- For extension-less CDN URLs, download the font into the repo with a properly named file and use that.
- If you control the server, rewrite the font route so URLs end with the real extension.
Example fix
// before — extension-less CDN URL url: 'https://cdn.example.com/fonts/123abc' // after — URL ends with a supported extension url: 'https://cdn.example.com/fonts/123abc.woff2'
Defensive patterns
Strategy: validation
Validate before calling
import { extname } from 'node:path';
const FONT_TYPES = ['woff2', 'woff', 'otf', 'ttf', 'eot'];
// run against every font url before build
for (const url of fontUrls) {
const ext = extname(new URL(url, 'file://localhost/').pathname).slice(1);
if (!FONT_TYPES.includes(ext)) {
throw new Error(`Font URL must end in one of ${FONT_TYPES.join(', ')}: ${url}`);
}
} Type guard
const hasSupportedFontExtension = (url: string): boolean =>
['woff2', 'woff', 'otf', 'ttf', 'eot'].includes(url.split('?')[0].split('.').pop() ?? ''); Prevention
- Name all font files with their real extension.
- Avoid id-keyed CDN URLs for fonts; use ones ending in the extension.
- Add an extension lint for the assets/fonts directory.
When it happens
Trigger: A font URL with no extension before the query string (`https://cdn.example.com/font?id=123`), an unsupported extension (`.ttc`, `.dfont`), or a path where the extension is swallowed by query/fragment placement.
Common situations: CDN URLs keyed by id instead of filename; renamed files losing their extension; using collection formats (.ttc) that the experimental Fonts API does not support.
Related errors
- FontFileUrlNotFound
- MissingGetFontFileRequestUrl
- font family cannot be retrieved by the provider. Did you…
- CannotDetermineWeightAndStyleFromFontFile
- CannotFetchFontFile
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/1436e322028bc2cb.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/assets/fonts/infra/node-font-type-extractor.ts:11
import { extname } from 'node:path';
import { AstroError, AstroErrorData } from '../../../core/errors/index.js';
import type { FontTypeExtractor } from '../definitions.js';
import type { FontType } from '../types.js';
import { isFontType } from '../utils.js';
export class NodeFontTypeExtractor implements FontTypeExtractor {
extract(url: string): FontType {
const extension = extname(url).slice(1);
if (!isFontType(extension)) {
throw new AstroError(
{
...AstroErrorData.CannotExtractFontType,
message: AstroErrorData.CannotExtractFontType.message(url),
},
{ cause: `Unexpected extension, got "${extension}"` },
);
}
return extension;
}
}
View on GitHub (pinned to 52e6c34790)