DavidHDev/react-bits · warning · Error

No @font-face rule found in the stylesheet

Error message

No @font-face rule found in the stylesheet

What it means

After successfully fetching the stylesheet CSS, loadFontFromStylesheet regex-matches /@font-face\s*{[^}]*}/g. If no blocks match (or none yield both family and url), family stays null and it throws. This means the fetched body was not valid @font-face CSS — e.g. an HTML intercept/captcha page returned with a 200 status, an empty body, or a format the regex cannot parse.

Source

Thrown at src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx:59

  const cssText = await response.text();
  const faceBlocks = cssText.match(/@font-face\s*{[^}]*}/g) || [];
  let family: string | null = null;
  const fontFaces: FontFace[] = [];
  for (const block of faceBlocks) {
    const familyMatch = block.match(/font-family:\s*['"]?([^;'"]+)['"]?/);
    const urlMatch = block.match(/url\(\s*['"]?([^'")]+)['"]?\s*\)/);
    if (!familyMatch || !urlMatch) continue;
    family = familyMatch[1].trim();
    const descriptors: FontFaceDescriptors = {};
    const weightMatch = block.match(/font-weight:\s*([^;]+);/);
    const styleMatch = block.match(/font-style:\s*([^;]+);/);
    const rangeMatch = block.match(/unicode-range:\s*([^;]+);/);
    if (weightMatch) descriptors.weight = weightMatch[1].trim();
    if (styleMatch) descriptors.style = styleMatch[1].trim();
    if (rangeMatch) descriptors.unicodeRange = rangeMatch[1].trim();
    fontFaces.push(new FontFace(family, `url(${urlMatch[1]})`, descriptors));
  }
  if (!family) throw new Error('No @font-face rule found in the stylesheet');
  await Promise.allSettled(
    fontFaces.map(async face => {
      await face.load();
      document.fonts.add(face);
    })
  );
  return family;
}

async function loadFontFromFile(url: string): Promise<string> {
  const family = deriveFontFamilyFromUrl(url);
  const fontFace = new FontFace(family, `url(${url})`);
  await fontFace.load();
  document.fonts.add(fontFace);
  return family;
}

async function loadCustomFont(fontUrl: string): Promise<string> {

View on GitHub (pinned to c7109dccb4)

Solutions

  1. Inspect the actual fetched body: log response.text() to confirm it is CSS with @font-face and not an HTML intercept page.
  2. Use a direct font-file URL (.woff2/.ttf) via fontUrl so loadFontFromFile runs instead of stylesheet parsing.
  3. Self-host the font CSS so you control its format and availability.
  4. Confirm the response Content-Type is text/css and status handling isn't masked by a proxy returning 200 + HTML.

Example fix

// before
const faceBlocks = cssText.match(/@font-face\s*{[^}]*}/g) || [];

// after (diagnose + prefer direct file)
console.debug('font css body:', cssText.slice(0, 200));
// pass a direct file instead of stylesheet:
<CircularGallery fontUrl='/fonts/Figtree.woff2' />
Defensive patterns

Strategy: validation

Validate before calling

function looksLikeFontStylesheet(css: string): boolean {
  return /@font-face\s*{/i.test(css) && /url\(/i.test(css);
}
// usage: only call loadFontFromStylesheet when looksLikeFontStylesheet(cssText) is true

Try / catch

try {
  family = await loadFontFromStylesheet(url);
} catch (e) {
  if (e instanceof Error && /No @font-face rule/.test(e.message)) {
    family = await loadFontFromFile(url); // try direct file path instead
  } else throw e;
}

Prevention

When it happens

Trigger: cssText (line 41) contains zero parseable @font-face blocks with both font-family and url() at src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx:42-59, so the family variable is never assigned.

Common situations: Captive portal / proxy returning HTML with HTTP 200; Google Fonts returning a browser-conditional CSS that differs from expected (rare); a user-supplied fontUrl pointing to an HTML page or JSON; response.text() truncated by an interceptor; minified/alternative CSS syntax the simple regex misses (e.g. src: with multiple url() and format() tokens — though the regex still finds the first url()).

Related errors


AI-assisted analysis of DavidHDev/react-bits@c7109dccb4 (2026-08-13). Data as JSON: /api/errors/7444bfe932755fec. Report an issue: GitHub.