vxcontrol/pentagi · error · FatalError

request failed: %s

Error message

request failed: %s

What it means

Fatal error from the Firecrawl searcher (backend/pkg/tools/searchers/firecrawl.go) returned when the Firecrawl API responds 200 with success=false and a non-empty error string in the body, or plain 'request failed' when no message is given. The search query was rejected by the service; not retryable.

Source

Thrown at backend/pkg/tools/searchers/firecrawl.go:183

	resp, err := client.Do(req)
	if err != nil {
		return "", Retryable(fmt.Errorf("failed to do request: %v", err), 0)
	}
	defer resp.Body.Close()

	return f.parseHTTPResponse(ctx, query, resp)
}

func (f *firecrawl) parseHTTPResponse(ctx context.Context, query string, resp *http.Response) (string, error) {
	switch resp.StatusCode {
	case http.StatusOK:
		var respBody firecrawlSearchResult
		if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
			return "", Fatal(fmt.Errorf("failed to decode response body: %v", err))
		}
		if !respBody.Success {
			if respBody.Error != "" {
				return "", Fatal(fmt.Errorf("request failed: %s", respBody.Error))
			}
			return "", Fatal(fmt.Errorf("request failed"))
		}
		return f.buildFirecrawlResult(ctx, query, &respBody), nil
	case http.StatusBadRequest:
		return "", Fatal(fmt.Errorf("request is invalid"))
	case http.StatusUnauthorized:
		return "", Fatal(fmt.Errorf("API key is wrong"))
	case http.StatusPaymentRequired:
		return "", Fatal(fmt.Errorf("insufficient credits to perform this request"))
	case http.StatusForbidden:
		return "", Fatal(fmt.Errorf("the endpoint requested is hidden for administrators only"))
	case http.StatusNotFound:
		return "", Fatal(fmt.Errorf("the specified endpoint could not be found"))
	case http.StatusMethodNotAllowed:
		return "", Fatal(fmt.Errorf("there need to try to access an endpoint with an invalid method"))
	case http.StatusRequestTimeout:
		return "", Retryable(fmt.Errorf("the request timed out. try again later"), 0)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Read the embedded upstream message (%s) for the exact vendor reason.
  2. Check Firecrawl dashboard for credits/quota and billing status.
  3. Retry later if the message indicates transient upstream failure; otherwise switch engines via fallback.
  4. Confirm API key belongs to an active, non-suspended team.

Example fix

// before: ignoring success flag
var r firecrawlSearchResult; json.Decode(&r); return r.Data
// after
if !r.Success { return "", Fatal(fmt.Errorf("request failed: %s", r.Error)) }
Defensive patterns

Strategy: fallback

Validate before calling

// check account status before heavy usage
info, err := firecrawlClient.CreditUsage(ctx)
if err == nil && info.Remaining <= 0 { return errors.New("firecrawl credits exhausted") }

Type guard

func isUpstreamFailure(res firecrawlSearchResult) bool { return !res.Success }

Try / catch

res, err := f.parseHTTPResponse(ctx, q, resp)
if err != nil {
  if !searchers.IsRetryable(err) { orchestrator.markEngineUnhealthy(f); useFallback(q) }
}

Prevention

When it happens

Trigger: POST /v2/search returns {"success":false,"error":"<engine message>"} — e.g. credits exhausted, job rejected, upstream scrape failure.

Common situations: Out of Firecrawl credits/quota on the account, engine-side crawl failure for the query, account suspended.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/24ce3d4c27d91553. Report an issue: GitHub.