firecrawl/open-lovable · error · Error

Firecrawl API error: ${error}

Error message

Firecrawl API error: ${error}

What it means

This error is thrown by the POST handler in app/api/scrape-url-enhanced/route.ts:66 when the raw fetch call to https://api.firecrawl.dev/v1/scrape returns a non-2xx HTTP status. The developer reads the response body as text and prefixes it with 'Firecrawl API error:' so the upstream API's error payload (e.g. 401 unauthorized, 402 payment required, 429 rate limit, 5xx) is surfaced verbatim. It is a generic wrapper for any Firecrawl HTTP-level failure, as opposed to the 2xx-but-unsuccessful case handled on the next lines.

Source

Thrown at app/api/scrape-url-enhanced/route.ts:66

        timeout: 30000,
        blockAds: true,
        maxAge: 3600000, // Use cached data if less than 1 hour old (500% faster!)
        actions: [
          {
            type: 'wait',
            milliseconds: 2000
          },
          {
            type: 'screenshot',
            fullPage: false // Just visible viewport for performance
          }
        ]
      })
    });
    
    if (!firecrawlResponse.ok) {
      const error = await firecrawlResponse.text();
      throw new Error(`Firecrawl API error: ${error}`);
    }
    
    const data = await firecrawlResponse.json();
    
    if (!data.success || !data.data) {
      throw new Error('Failed to scrape content');
    }
    
    const { markdown, metadata, screenshot, actions } = data.data;
    // html available but not used in current implementation
    
    // Get screenshot from either direct field or actions result
    const screenshotUrl = screenshot || actions?.screenshots?.[0] || null;
    
    // Sanitize the markdown content
    const sanitizedMarkdown = sanitizeQuotes(markdown || '');
    
    // Extract structured data from the response

View on GitHub (pinned to 69bd93bae7)

Solutions

  1. Log firecrawlResponse.status alongside the body text so the actual upstream cause (401 vs 402 vs 429 vs 5xx) is visible, then fix that specific cause first.
  2. Verify FIRECRAWL_API_KEY is set in the deployment environment and is valid — test with curl -H 'Authorization: Bearer $KEY' https://api.firecrawl.dev/v1/scrape.
  3. Check your Firecrawl dashboard for credit/plan exhaustion or rate limits; upgrade the plan or add backoff/retry on 429.
  4. Retry transient failures (429/5xx) with exponential backoff; for slow sites consider raising the timeout/waitFor options or dropping the extra screenshot actions.
  5. Return a structured error to the client (status code plus sanitized message) instead of leaking the raw upstream response body.

Example fix

// before
if (!firecrawlResponse.ok) {
  const error = await firecrawlResponse.text();
  throw new Error(`Firecrawl API error: ${error}`);
}
// after
if (!firecrawlResponse.ok) {
  const error = await firecrawlResponse.text();
  if (firecrawlResponse.status === 429 || firecrawlResponse.status >= 500) {
    // retry with backoff, e.g. via p-retry
  }
  console.error(`Firecrawl scrape failed (${firecrawlResponse.status}):`, error);
  return NextResponse.json({ success: false, error: `Scrape failed (${firecrawlResponse.status})` }, { status: firecrawlResponse.status === 401 ? 500 : 502 });
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!process.env.FIRECRAWL_API_KEY) {
  throw new Error('FIRECRAWL_API_KEY is not configured');
}
try { new URL(url); } catch { throw new Error(`Invalid URL: ${url}`); }

Type guard

function isFirecrawlOk(res: Response) { return res.ok; }

Try / catch

try {
  const res = await fetch('https://api.firecrawl.dev/v1/scrape', { ... });
  if (!res.ok) {
    const body = await res.text();
    if (res.status === 429 || res.status >= 500) throw new RetryableError(`Firecrawl ${res.status}: ${body}`);
    throw new Error(`Firecrawl ${res.status}: ${body.slice(0, 300)}`);
  }
} catch (e) {
  if (e instanceof RetryableError) { /* backoff + retry */ }
  return NextResponse.json({ success: false, error: 'Scrape unavailable' }, { status: 502 });
}

Prevention

When it happens

Trigger: Any POST to /api/scrape-url-enhanced where api.firecrawl.dev/v1/scrape responds with a non-ok status: invalid or missing FIRECRAWL_API_KEY (401), exhausted credits/plan limit (402/429), malformed request body (400), a URL Firecrawl refuses to scrape (blocked/paywalled site), or Firecrawl-side outage/timeout exceeding the 30000ms timeout option.

Common situations: Deployed app where FIRECRAWL_API_KEY env var was never set or rotated/revoked; free-tier credit exhaustion after heavy scraping; scraping sites that block bots (403) or require JS/captcha; passing internal/localhost URLs which Firecrawl rejects; Firecrawl incidents or rate limiting under concurrent load.

Related errors


AI-assisted analysis of firecrawl/open-lovable@69bd93bae7 (2026-08-28). Data as JSON: /api/errors/d5f3421936120da4. Report an issue: GitHub.