DavidHDev/react-bits · warning · Error
Failed to fetch font stylesheet (${response.status})
Error message
Failed to fetch font stylesheet (${response.status}) What it means
loadFontFromStylesheet fetches a CSS file (Google Fonts Figtree by default) and throws when response.ok is false. The HTTP status is embedded in the message. This is a network/HTTP-level failure on the font CSS request; the font files themselves are fetched later. The outer resolveFont (line 116-119) catches this and falls back to the default font string, so it is non-fatal to rendering.
Source
Thrown at src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx:40
instance[key] = instance[key].bind(instance);
}
});
}
const DEFAULT_FONT = 'bold 30px Figtree';
// Figtree is not guaranteed to be available on the host page, so the component
// loads it on demand whenever the default font is used.
const DEFAULT_FONT_URL = 'https://fonts.googleapis.com/css2?family=Figtree:wght@400;700&display=swap';
function deriveFontFamilyFromUrl(url: string): string {
const fileName = (url.split('/').pop() || 'custom-font').split('?')[0];
const base = fileName.replace(/\.(woff2?|ttf|otf|eot)$/i, '');
return base.replace(/[^a-zA-Z0-9-_ ]/g, '').trim() || 'CircularGalleryFont';
}
async function loadFontFromStylesheet(url: string): Promise<string> {
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to fetch font stylesheet (${response.status})`);
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));
}View on GitHub (pinned to c7109dccb4)
Solutions
- Allow the font host in CSP: add fonts.googleapis.com and fonts.gstatic.com to connect-src and font-src.
- Verify network reachability to the stylesheet URL from the user's environment (e.g. curl -I the URL).
- Bundle the font file locally and pass a direct .woff2 URL via the fontUrl prop instead of the Google stylesheet.
- Rely on the built-in fallback: resolveFont already catches this and renders with the default font — confirm the error is only logged, not crashing.
Example fix
// before
const DEFAULT_FONT_URL = 'https://fonts.googleapis.com/css2?family=Figtree:wght@400;700&display=swap';
// after (self-host to remove network/CSP dependency)
import figtreeUrl from './assets/Figtree.woff2';
<CircularGallery fontUrl={figtreeUrl} />
// and relax CSP only if still using Google Fonts:
// Content-Security-Policy: ... connect-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; Defensive patterns
Strategy: try-catch
Validate before calling
async function canFetchStylesheet(url: string): Promise<boolean> {
try {
const r = await fetch(url, { method: 'GET' });
return r.ok;
} catch { return false; }
} Try / catch
// resolveFont already does this (CircularGallery.tsx:116-119):
try {
const family = await loadCustomFont(effectiveUrl);
return `${prefix} "${family}"`;
} catch (error) {
console.error('CircularGallery: unable to load font from', fontUrl, error);
return font; // fall back to the default font string
} Prevention
- Allow fonts.googleapis.com / fonts.gstatic.com in CSP connect-src and font-src.
- Self-host the font file and pass a direct .woff2 URL via fontUrl.
- Verify network reachability to the stylesheet from the user's environment.
- Rely on the built-in fallback in resolveFont rather than letting it crash.
When it happens
Trigger: fetch(url).then(r => !r.ok -> throw) at src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx:40, where url is DEFAULT_FONT_URL ('https://fonts.googleapis.com/css2?family=Figtree...') or a caller-supplied fontUrl matched as a stylesheet (line 78).
Common situations: Offline or blocked network; Content-Security-Policy connect-src/font-src blocking fonts.googleapis.com; corporate firewall/proxy returning a 4xx/5xx intercept page; Google Fonts rate-limiting (429); geographic blocking; jsdom where fetch is a stub returning non-ok; invalid/expired stylesheet URL.
Related errors
AI-assisted analysis of DavidHDev/react-bits@c7109dccb4 (2026-08-13).
Data as JSON: /api/errors/96fa548af007273e.
Report an issue: GitHub.