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

  1. 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).
  2. For extension-less CDN URLs, download the font into the repo with a properly named file and use that.
  3. 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

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


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)