vxcontrol/pentagi · error · Fatal

unexpected status code: %d

Error message

unexpected status code: %d

What it means

parseHTTPResponse's default branch wraps any Tavily response status not explicitly handled (not 429/500/502/503/504) into a Fatal error: 'unexpected status code: %d'. Fatal means retrying the same engine is pointless — the caller should fall back to another searcher or surface the error.

Source

Thrown at backend/pkg/tools/searchers/tavily.go:170

		return "", Fatal(fmt.Errorf("API key is wrong"))
	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.StatusTooManyRequests:
		return "", Retryable(fmt.Errorf("there are requesting too many results"), 0)
	case http.StatusInternalServerError:
		return "", Retryable(fmt.Errorf("there had a problem with our server. try again later"), 0)
	case http.StatusBadGateway:
		return "", Retryable(fmt.Errorf("there was a problem with the server. Please try again later"), 0)
	case http.StatusServiceUnavailable:
		return "", Retryable(fmt.Errorf("there are temporarily offline for maintenance. please try again later"), 0)
	case http.StatusGatewayTimeout:
		return "", Retryable(fmt.Errorf("there are temporarily offline for maintenance. please try again later"), 0)
	default:
		return "", Fatal(fmt.Errorf("unexpected status code: %d", resp.StatusCode))
	}
}

func (t *tavily) buildTavilyResult(ctx context.Context, result *tavilySearchResult) string {
	var writer strings.Builder
	writer.WriteString("# Answer\n\n")
	writer.WriteString(result.Answer)
	writer.WriteString("\n\n# Links\n\n")

	isRawContentExists := false
	for i, result := range result.Results {
		writer.WriteString(fmt.Sprintf("## %d. %s\n\n", i+1, result.Title))
		writer.WriteString(fmt.Sprintf("* URL %s\n", result.URL))
		writer.WriteString(fmt.Sprintf("* Match score %3.3f\n\n", result.Score))
		writer.WriteString(fmt.Sprintf("### Short content\n\n%s\n\n", result.Content))
		if result.RawContent != nil {
			isRawContentExists = true
		}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Log the actual status code — the message includes it via %d — and fix the root cause (usually auth).
  2. Verify TAVILY_API_KEY is set and valid; test with curl against api.tavily.com.
  3. Update the searcher if Tavily introduced new status codes worth handling explicitly.
  4. Ensure the orchestrator treats Fatal errors by switching engines, not retrying.

Example fix

// before: ignoring the status code detail
if err != nil { return "", err }
// after: inspect wrapped error and remediate auth issues
var fatal *searchers.FatalError
if errors.As(err, &fatal) && strings.Contains(fatal.Error(), "401") {
    return "", fmt.Errorf("tavily auth failed: check TAVILY_API_KEY")
}
Defensive patterns

Strategy: fallback

Validate before calling

if os.Getenv("TAVILY_API_KEY") == "" {
    return errors.New("TAVILY_API_KEY not configured; tavily engine unavailable")
}

Type guard

func isFatalSearcherError(err error) bool {
    var f *searchers.FatalError
    return errors.As(err, &f)
}

Try / catch

result, err := tavilySearcher.Handle(ctx, req)
var f *searchers.FatalError
if errors.As(err, &f) {
    log.Errorf("tavily fatal: %v", f)
    return fallbackEngine.Handle(ctx, req)
}

Prevention

When it happens

Trigger: Any non-200 status outside the handled set — e.g. 400 Bad Request from a malformed query, 401/403 from an invalid or expired TAVILY_API_KEY, 404 from a changed API endpoint, or 418/429 edge cases not matched.

Common situations: Expired or wrong Tavily API key (401/403); Tavily API contract change (new status codes); request blocked by WAF (403); malformed plan/billing state (402).

Related errors


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