firecrawl/open-lovable · error · Error

Search failed

Error message

Search failed

What it means

Thrown at app/api/search/route.ts:29 when the raw fetch to https://api.firecrawl.dev/v1/search returns a non-ok HTTP status. Unlike the scrape routes, this handler discards the response body and status, so the real upstream cause (401 bad key, 429 quota, 400 bad query, 5xx outage) is lost and every failure surfaces as the opaque string 'Search failed'. The catch block then converts it into a 500 'Failed to perform search' for the client.

Source

Thrown at app/api/search/route.ts:29

    // Use Firecrawl search to get top 10 results with screenshots
    const searchResponse = await fetch('https://api.firecrawl.dev/v1/search', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.FIRECRAWL_API_KEY}`,
      },
      body: JSON.stringify({
        query,
        limit: 10,
        scrapeOptions: {
          formats: ['markdown', 'screenshot'],
          onlyMainContent: true,
        },
      }),
    });

    if (!searchResponse.ok) {
      throw new Error('Search failed');
    }

    const searchData = await searchResponse.json();
    
    // Format results with screenshots and markdown
    const results = searchData.data?.map((result: any) => ({
      url: result.url,
      title: result.title || result.url,
      description: result.description || '',
      screenshot: result.screenshot || null,
      markdown: result.markdown || '',
    })) || [];

    return NextResponse.json({ results });
  } catch (error) {
    console.error('Search error:', error);
    return NextResponse.json(
      { error: 'Failed to perform search' },

View on GitHub (pinned to 69bd93bae7)

Solutions

  1. Capture searchResponse.status and body text in the thrown error/log so the true cause is diagnosable — this is the single most important fix.
  2. Verify FIRECRAWL_API_KEY is set in the environment (this route, unlike scrape-website, never checks for it and silently sends an empty credential).
  3. Confirm the /v1/search request payload (limit:10, scrapeOptions formats) against current Firecrawl docs; invalid scrapeOptions can yield 400.
  4. Add retry with backoff for 429/5xx responses and return a mapped status (401->misconfigured, 429->rate limited) instead of a blanket 500.
  5. Set up a Firecrawl status/health check or alerting so outages are recognized quickly.

Example fix

// before
if (!searchResponse.ok) {
  throw new Error('Search failed');
}
// after
if (!searchResponse.ok) {
  const detail = await searchResponse.text();
  console.error(`Firecrawl search failed (${searchResponse.status}):`, detail);
  throw new Error(`Search failed (${searchResponse.status}): ${detail.slice(0, 200)}`);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const FIRECRAWL_API_KEY = process.env.FIRECRAWL_API_KEY;
if (!FIRECRAWL_API_KEY) throw new Error('FIRECRAWL_API_KEY is not set');
if (typeof query !== 'string' || query.trim().length === 0) throw new Error('Query is required');

Type guard

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

Try / catch

const res = await fetch('https://api.firecrawl.dev/v1/search', { ... });
if (!res.ok) {
  const detail = await res.text().catch(() => '');
  throw new Error(`Firecrawl search ${res.status}: ${detail.slice(0, 200)}`);
}
// in outer catch:
catch (e) {
  console.error('Search error:', e);
  const status = (e as Error).message.includes('401') ? 503 : 502;
  return NextResponse.json({ error: 'Search unavailable, try again later' }, { status });
}

Prevention

When it happens

Trigger: Any POST /api/search where the Firecrawl /v1/search endpoint responds non-2xx: missing/invalid FIRECRAWL_API_KEY, exhausted credits or rate limit, a query payload Firecrawl rejects (e.g. unsupported scrapeOptions combination like markdown+screenshot), or a Firecrawl service outage.

Common situations: Environment without FIRECRAWL_API_KEY configured (the header becomes 'Bearer undefined' and Firecrawl returns 401); free-tier quota exhausted after many searches; sending scrapeOptions fields not supported by the deployed Firecrawl version; network/egress restrictions in the hosting environment blocking api.firecrawl.dev.

Related errors


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