{"record":{"id":"52deb8d1234c9c8f","repo":"firecrawl/open-lovable","slug":"firecrawl-api-returned-firecrawlresponse-status","errorCode":null,"errorMessage":"Firecrawl API returned ${firecrawlResponse.status}","messagePattern":"Firecrawl API returned (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/api/extract-brand-styles/route.ts","lineNumber":37,"sourceCode":"\n    console.log('[extract-brand-styles] Calling Firecrawl branding API for:', url);\n\n    const firecrawlResponse = await fetch('https://api.firecrawl.dev/v2/scrape', {\n      method: 'POST',\n      headers: {\n        'Authorization': `Bearer ${FIRECRAWL_API_KEY}`,\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        url: url,\n        formats: ['branding'],\n      }),\n    });\n\n    if (!firecrawlResponse.ok) {\n      const errorText = await firecrawlResponse.text();\n      console.error('[extract-brand-styles] Firecrawl API error:', firecrawlResponse.status, errorText);\n      throw new Error(`Firecrawl API returned ${firecrawlResponse.status}`);\n    }\n\n    const firecrawlData = await firecrawlResponse.json();\n    console.log('[extract-brand-styles] Firecrawl response received successfully');\n\n    // Extract branding data from response\n    const brandingData = firecrawlData.data?.branding || firecrawlData.branding;\n\n    if (!brandingData) {\n      console.error('[extract-brand-styles] No branding data in Firecrawl response');\n      console.log('[extract-brand-styles] Response structure:', JSON.stringify(firecrawlData, null, 2));\n      throw new Error('No branding data in Firecrawl response');\n    }\n\n    console.log('[extract-brand-styles] Successfully extracted branding data');\n\n    // Return the branding data\n    return NextResponse.json({","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/firecrawl/open-lovable/blob/69bd93bae7a9c97ef989eb70aabe6797fb3dac89/app/api/extract-brand-styles/route.ts#L19-L55","documentation":"Thrown when the Firecrawl v2 scrape endpoint responds with a non-2xx HTTP status. The response body (error text from Firecrawl) is logged to the server console, and the route raises this error so the caller knows brand extraction failed upstream.","triggerScenarios":"POST /api/extract-brand-styles with a request that Firecrawl rejects: invalid or expired API key (401), rate limit / quota exceeded (402/429), malformed URL (400), or Firecrawl outage (5xx).","commonSituations":"Free-tier credits exhausted; a URL that requires JS rendering beyond plan limits; temporarily down api.firecrawl.dev; sending an unreachable or private-network URL.","solutions":["Read the server console log '[extract-brand-styles] Firecrawl API error' — the status and Firecrawl's error text identify the cause","401/403: verify FIRECRAWL_API_KEY is valid and active on firecrawl.dev","402/429: check plan credits and rate limits; upgrade or wait and retry","Include the response body in the thrown message to make client-side debugging easier"],"exampleFix":"// before\nthrow new Error(`Firecrawl API returned ${firecrawlResponse.status}`);\n// after\nconst errorText = await firecrawlResponse.text();\nif (firecrawlResponse.status === 429) {\n  throw new Error('Firecrawl rate limit exceeded, retry later');\n}\nthrow new Error(`Firecrawl API returned ${firecrawlResponse.status}: ${errorText.slice(0, 200)}`);","handlingStrategy":"retry","validationCode":"const url = new URL(userUrl);\nif (!/^https?:$/.test(url.protocol)) throw new Error('Only http(s) URLs can be scraped');","typeGuard":"function isOk(res: Response): boolean { return res.status >= 200 && res.status < 300; }","tryCatchPattern":"try {\n  return await extractBrandStyles(url);\n} catch (e) {\n  if (/returned (429|5\\d\\d)/.test(e.message)) {\n    await sleep(2000);\n    return extractBrandStyles(url); // retry transient failures once\n  }\n  if (/returned 40[13]/.test(e.message)) {\n    throw new Error('Check FIRECRAWL_API_KEY — Firecrawl rejected authentication');\n  }\n  throw e;\n}","preventionTips":["Include the Firecrawl response body in error messages for faster diagnosis","Monitor plan credits and rate limits on firecrawl.dev","Retry only transient statuses (429, 5xx) with backoff","Pre-validate URLs (protocol, reachability) before calling Firecrawl"],"tags":["network","http-status","firecrawl","third-party-api"],"backgroundTag":"upstream-http-error","analyzedSha":"69bd93bae7a9c97ef989eb70aabe6797fb3dac89","analyzedAt":"2026-08-28T22:20:32.339Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}