{"record":{"id":"9fec75d1348cad47","repo":"firecrawl/open-lovable","slug":"failed-to-extract-brand-styles","errorCode":null,"errorMessage":"Failed to extract brand styles","messagePattern":"Failed to extract brand styles","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/generation/page.tsx","lineNumber":2728,"sourceCode":"        let scrapeData: ScrapeData | undefined;\n        let brandGuidelines: any;\n\n        if (brandExtensionMode) {\n          // === BRAND EXTENSION MODE ===\n          addChatMessage('Extracting brand styles from the website...', 'system');\n\n          // Call the brand extraction endpoint\n          const extractResponse = await fetch('/api/extract-brand-styles', {\n            method: 'POST',\n            headers: { 'Content-Type': 'application/json' },\n            body: JSON.stringify({\n              url,\n              prompt: brandExtensionPrompt\n            })\n          });\n\n          if (!extractResponse.ok) {\n            throw new Error('Failed to extract brand styles');\n          }\n\n          brandGuidelines = await extractResponse.json();\n\n          if (!brandGuidelines.success) {\n            throw new Error(brandGuidelines.error || 'Failed to extract brand styles');\n          }\n\n          // Display branding summary with visual UI\n          addChatMessage(`Acquired branding format from ${cleanUrl}`, 'system', {\n            brandingData: brandGuidelines.guidelines,\n            sourceUrl: cleanUrl\n          });\n          addChatMessage(`Building your custom component using these brand guidelines...`, 'system');\n\n          // Clear the flags after use\n          sessionStorage.removeItem('brandExtensionMode');\n          sessionStorage.removeItem('brandExtensionPrompt');","sourceCodeStart":2710,"sourceCodeEnd":2746,"githubUrl":"https://github.com/firecrawl/open-lovable/blob/69bd93bae7a9c97ef989eb70aabe6797fb3dac89/app/generation/page.tsx#L2710-L2746","documentation":"Thrown when the brand-styles extraction endpoint returns a non-2xx HTTP status during brand-extension mode. The client posted { url, prompt: brandExtensionPrompt } and extractResponse.ok was false, so the brand guidelines could not be fetched and generation of the brand-matched component cannot proceed. It is a coarse message: the HTTP status/body must be checked separately for the real cause.","triggerScenarios":"fetch to the extract-brand-styles route resolves with extractResponse.ok === false: the target site blocked scraping (403 from upstream, surfaced as route failure), the route handler threw (invalid URL, fetch timeout), or the route is missing (404).","commonSituations":"User submits a URL behind a login/Cloudflare protection so server-side scraping is blocked; malformed URL (missing protocol) fails server-side URL validation; extraction route times out on slow sites; deployment lacks the extraction route; target site returns non-HTML content the extractor cannot parse and the route 500s.","solutions":["Inspect the Network tab for the extraction request's status code and body to see the underlying reason","Validate the URL is well-formed and publicly reachable (try curl-ing it) before retrying","If the site blocks bots (403/Cloudflare), try a different public page of the same brand or a cached version","Check the extraction route's server logs for timeouts or upstream fetch errors and increase its timeout if needed","Retry once for transient 5xx/timeout failures"],"exampleFix":"// before\nif (!extractResponse.ok) {\n  throw new Error('Failed to extract brand styles');\n}\n// after\nif (!extractResponse.ok) {\n  let detail = '';\n  try { detail = await extractResponse.text(); } catch {}\n  throw new Error(`Failed to extract brand styles (${extractResponse.status}): ${detail || extractResponse.statusText}`);\n}","handlingStrategy":"validation","validationCode":"function isExtractableUrl(url: string): boolean {\n  try { const u = new URL(url); return u.protocol === 'http:' || u.protocol === 'https:'; }\n  catch { return false; }\n}\nif (!isExtractableUrl(url)) throw new Error('Enter a valid public http(s) URL');","typeGuard":"interface BrandGuidelines { success: boolean; error?: string; guidelines?: unknown }\nfunction hasGuidelines(d: unknown): d is BrandGuidelines & { success: true; guidelines: Record<string, unknown> } {\n  return typeof d === 'object' && d !== null && (d as BrandGuidelines).success === true && (d as BrandGuidelines).guidelines != null;\n}","tryCatchPattern":"try {\n  const res = await fetch(EXTRACT_URL, { method: 'POST', body: JSON.stringify({ url, prompt: brandExtensionPrompt }) });\n  if (!res.ok) throw new Error(`Brand extraction HTTP ${res.status}`);\n  brandGuidelines = await res.json();\n  if (!hasGuidelines(brandGuidelines)) throw new Error(brandGuidelines?.error || 'No usable brand guidelines extracted');\n} catch (err: any) {\n  addChatMessage(`Brand extraction failed: ${err.message}. Try another public page.`, 'system');\n}","preventionTips":["Validate URL format and scheme client-side before submitting","Prefer public, static-HTML pages; warn users about login-walled or bot-protected sites","Read the extraction response body for the real cause instead of a generic message","Set/verify a reasonable server-side fetch timeout for slow sites","Fall back to manual brand input when automated extraction fails"],"tags":["network","scraping","branding","http-status"],"backgroundTag":"scrape-request-blocked","analyzedSha":"69bd93bae7a9c97ef989eb70aabe6797fb3dac89","analyzedAt":"2026-08-28T22:20:32.339Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}