{"record":{"id":"96fa548af007273e","repo":"DavidHDev/react-bits","slug":"failed-to-fetch-font-stylesheet-response-status","errorCode":null,"errorMessage":"Failed to fetch font stylesheet (${response.status})","messagePattern":"Failed to fetch font stylesheet \\((.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx","lineNumber":40,"sourceCode":"      instance[key] = instance[key].bind(instance);\n    }\n  });\n}\n\nconst DEFAULT_FONT = 'bold 30px Figtree';\n// Figtree is not guaranteed to be available on the host page, so the component\n// loads it on demand whenever the default font is used.\nconst DEFAULT_FONT_URL = 'https://fonts.googleapis.com/css2?family=Figtree:wght@400;700&display=swap';\n\nfunction deriveFontFamilyFromUrl(url: string): string {\n  const fileName = (url.split('/').pop() || 'custom-font').split('?')[0];\n  const base = fileName.replace(/\\.(woff2?|ttf|otf|eot)$/i, '');\n  return base.replace(/[^a-zA-Z0-9-_ ]/g, '').trim() || 'CircularGalleryFont';\n}\n\nasync function loadFontFromStylesheet(url: string): Promise<string> {\n  const response = await fetch(url);\n  if (!response.ok) throw new Error(`Failed to fetch font stylesheet (${response.status})`);\n  const cssText = await response.text();\n  const faceBlocks = cssText.match(/@font-face\\s*{[^}]*}/g) || [];\n  let family: string | null = null;\n  const fontFaces: FontFace[] = [];\n  for (const block of faceBlocks) {\n    const familyMatch = block.match(/font-family:\\s*['\"]?([^;'\"]+)['\"]?/);\n    const urlMatch = block.match(/url\\(\\s*['\"]?([^'\")]+)['\"]?\\s*\\)/);\n    if (!familyMatch || !urlMatch) continue;\n    family = familyMatch[1].trim();\n    const descriptors: FontFaceDescriptors = {};\n    const weightMatch = block.match(/font-weight:\\s*([^;]+);/);\n    const styleMatch = block.match(/font-style:\\s*([^;]+);/);\n    const rangeMatch = block.match(/unicode-range:\\s*([^;]+);/);\n    if (weightMatch) descriptors.weight = weightMatch[1].trim();\n    if (styleMatch) descriptors.style = styleMatch[1].trim();\n    if (rangeMatch) descriptors.unicodeRange = rangeMatch[1].trim();\n    fontFaces.push(new FontFace(family, `url(${urlMatch[1]})`, descriptors));\n  }","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/DavidHDev/react-bits/blob/c7109dccb42e06592d1d9bc50bc87204697240e2/src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx#L22-L58","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nconst DEFAULT_FONT_URL = 'https://fonts.googleapis.com/css2?family=Figtree:wght@400;700&display=swap';\n\n// after (self-host to remove network/CSP dependency)\nimport figtreeUrl from './assets/Figtree.woff2';\n<CircularGallery fontUrl={figtreeUrl} />\n\n// and relax CSP only if still using Google Fonts:\n// Content-Security-Policy: ... connect-src 'self' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com;","handlingStrategy":"try-catch","validationCode":"async function canFetchStylesheet(url: string): Promise<boolean> {\n  try {\n    const r = await fetch(url, { method: 'GET' });\n    return r.ok;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"// resolveFont already does this (CircularGallery.tsx:116-119):\ntry {\n  const family = await loadCustomFont(effectiveUrl);\n  return `${prefix} \"${family}\"`;\n} catch (error) {\n  console.error('CircularGallery: unable to load font from', fontUrl, error);\n  return font; // fall back to the default font string\n}","preventionTips":["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."],"tags":["network","font","fetch","http-status","csp","circular-gallery"],"backgroundTag":null,"analyzedSha":"c7109dccb42e06592d1d9bc50bc87204697240e2","analyzedAt":"2026-08-13T02:32:07.327Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}