{"record":{"id":"7444bfe932755fec","repo":"DavidHDev/react-bits","slug":"no-font-face-rule-found-in-the-stylesheet","errorCode":null,"errorMessage":"No @font-face rule found in the stylesheet","messagePattern":"No @font-face rule found in the stylesheet","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx","lineNumber":59,"sourceCode":"  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  }\n  if (!family) throw new Error('No @font-face rule found in the stylesheet');\n  await Promise.allSettled(\n    fontFaces.map(async face => {\n      await face.load();\n      document.fonts.add(face);\n    })\n  );\n  return family;\n}\n\nasync function loadFontFromFile(url: string): Promise<string> {\n  const family = deriveFontFamilyFromUrl(url);\n  const fontFace = new FontFace(family, `url(${url})`);\n  await fontFace.load();\n  document.fonts.add(fontFace);\n  return family;\n}\n\nasync function loadCustomFont(fontUrl: string): Promise<string> {","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/DavidHDev/react-bits/blob/c7109dccb42e06592d1d9bc50bc87204697240e2/src/ts-tailwind/Components/CircularGallery/CircularGallery.tsx#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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()).","solutions":["Inspect the actual fetched body: log response.text() to confirm it is CSS with @font-face and not an HTML intercept page.","Use a direct font-file URL (.woff2/.ttf) via fontUrl so loadFontFromFile runs instead of stylesheet parsing.","Self-host the font CSS so you control its format and availability.","Confirm the response Content-Type is text/css and status handling isn't masked by a proxy returning 200 + HTML."],"exampleFix":"// before\nconst faceBlocks = cssText.match(/@font-face\\s*{[^}]*}/g) || [];\n\n// after (diagnose + prefer direct file)\nconsole.debug('font css body:', cssText.slice(0, 200));\n// pass a direct file instead of stylesheet:\n<CircularGallery fontUrl='/fonts/Figtree.woff2' />","handlingStrategy":"validation","validationCode":"function looksLikeFontStylesheet(css: string): boolean {\n  return /@font-face\\s*{/i.test(css) && /url\\(/i.test(css);\n}\n// usage: only call loadFontFromStylesheet when looksLikeFontStylesheet(cssText) is true","typeGuard":null,"tryCatchPattern":"try {\n  family = await loadFontFromStylesheet(url);\n} catch (e) {\n  if (e instanceof Error && /No @font-face rule/.test(e.message)) {\n    family = await loadFontFromFile(url); // try direct file path instead\n  } else throw e;\n}","preventionTips":["Inspect the fetched CSS body before parsing (log response.text()).","Prefer direct font-file URLs (.woff2) over stylesheets via fontUrl.","Self-host the font CSS so you control its format and availability.","Confirm the response is text/css and not an HTML intercept page."],"tags":["font","regex","parsing","network","circular-gallery"],"backgroundTag":null,"analyzedSha":"c7109dccb42e06592d1d9bc50bc87204697240e2","analyzedAt":"2026-08-13T02:32:07.327Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}