mastra-ai/mastra · error · Error

${response.error || 'Scraping failed'}

Error message

${response.error || 'Scraping failed'}

What it means

After `client.scrapeUrl` returns, the executor checks `response.success`; when it is explicitly false it throws `response.error || 'Scraping failed'`. This surfaces a Firecrawl API-side failure (bad key, blocked page, scrape timeout) as the tool's error message. Note the inner try/catch converts it into an `isError: true` MCP result rather than a thrown exception.

Source

Thrown at packages/mcp/src/__fixtures__/fire-crawl-complex-schema.ts:639

    switch (originalName) {
      case 'firecrawl_scrape': {
        if (!isScrapeOptions(args)) {
          throw new Error('Invalid arguments for firecrawl_scrape');
        }
        const { url, ...options } = args;
        try {
          const scrapeStartTime = Date.now();
          safeLog('info', `Starting scrape for URL: ${url} with options: ${JSON.stringify(options)}`);

          const response = await client.scrapeUrl(url, {
            ...options,
          });

          safeLog('info', `Scrape completed in ${Date.now() - scrapeStartTime}ms`);

          if ('success' in response && !response.success) {
            throw new Error(response.error || 'Scraping failed');
          }

          const contentParts = [];

          if (options.formats?.includes('markdown') && response.markdown) {
            contentParts.push(response.markdown);
          }
          if (options.formats?.includes('html') && response.html) {
            contentParts.push(response.html);
          }
          if (options.formats?.includes('rawHtml') && response.rawHtml) {
            contentParts.push(response.rawHtml);
          }
          if (options.formats?.includes('links') && response.links) {
            contentParts.push(response.links.join('\n'));
          }
          if (options.formats?.includes('screenshot') && response.screenshot) {
            contentParts.push(response.screenshot);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the `response.error` message; fix the underlying cause it names (auth, credits, URL).
  2. Verify FIRECRAWL_API_KEY is valid and has remaining credits in the Firecrawl dashboard.
  3. Retry with adjusted scrape options (longer timeout, waitUntil, formats limited to markdown).
  4. Add rate-limit/backoff handling (the fixture's withRetry only covers the crawl path).

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: key and URL sanity checks
if (!process.env.FIRECRAWL_API_KEY) throw new Error('FIRECRAWL_API_KEY missing');
new URL(input.url); // throws on malformed URL

Type guard

function isFailedScrape(r: unknown): r is { success: false; error?: string } {
  return typeof r === 'object' && r !== null && 'success' in r && (r as any).success === false;
}

Try / catch

try {
  const res = await client.scrapeUrl(url, { formats: ['markdown'] });
  if ('success' in res && !res.success) throw new Error(res.error || 'Scraping failed');
} catch (e) {
  const msg = (e as Error).message;
  if (/401|403|unauthorized/i.test(msg)) rotateApiKey();
  else if (/credit|quota/i.test(msg)) escalateToBilling();
  else if (/timeout|blocked/i.test(msg)) await scrapeWithLongerTimeout(url);
}

Prevention

When it happens

Trigger: Any scrape where the Firecrawl API responds with success:false — invalid/expired API key, credits exhausted, target URL unreachable or blocking crawlers (403/timeout), or an unsupported format combination.

Common situations: FIRECRAWL_API_KEY not set or rotated, free-tier credit limits hit, scraping sites protected by Cloudflare/bot walls, scraping URLs that require JS rendering without `waitUntil`/timeout tuning.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/f1e125e97e445660. Report an issue: GitHub.