vxcontrol/pentagi · error

unexpected status code: %d

Error message

unexpected status code: %d

What it means

parseHTTPResponse rejects any SearxNG response whose status is not 200. The raw status code is embedded in the error message; 429 or any 5xx is classified Retryable (orchestrator may retry/fall back), everything else (4xx like 401/403/404) is Fatal. Note that the dedicated /search JSON API requires the 'format=json' parameter — SearxNG returns 403 when JSON format is disabled or forbidden by the instance settings (search.format setting).

Source

Thrown at backend/pkg/tools/searchers/searxng.go:134

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL.String(), nil)
	if err != nil {
		return "", Fatal(fmt.Errorf("failed to create request: %w", err))
	}

	req.Header.Set("User-Agent", "PentAGI/1.0")

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

	return s.parseHTTPResponse(resp, query)
}

func (s *searxng) parseHTTPResponse(resp *http.Response, query string) (string, error) {
	if resp.StatusCode != http.StatusOK {
		err := fmt.Errorf("unexpected status code: %d", resp.StatusCode)
		if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {
			return "", Retryable(err, 0)
		}
		return "", Fatal(err)
	}

	var searxngResponse SearxngResponse
	if err := json.NewDecoder(resp.Body).Decode(&searxngResponse); err != nil {
		return "", Fatal(fmt.Errorf("failed to decode response body: %w", err))
	}

	return s.formatResults(searxngResponse.Results, query), nil
}

func (s *searxng) formatResults(results []SearxngResult, query string) string {
	if len(results) == 0 {
		return fmt.Sprintf("# No Results Found\n\nNo results were found for query: %s", query)
	}

View on GitHub (pinned to ea665308ba)

Solutions

  1. Enable JSON output in SearxNG settings.yml: under search: add 'formats: [html, json]' and restart the instance (fixes 403)
  2. If 429: check the limiter plugin config or raise rate limits; this error is Retryable so backoff may suffice
  3. If 404: confirm the instance serves /search at the configured SEARXNG_URL path (trailing path handled automatically, but reverse-proxy rewrites can break it)
  4. If 401: configure the auth token expected by the instance or remove the auth plugin
  5. Check SearxNG container logs for the request to correlate the rejected status

Example fix

// before (searxng settings.yml)
search:
  formats:
    - html
// after (searxng settings.yml)
search:
  formats:
    - html
    - json
Defensive patterns

Strategy: fallback

Validate before calling

// verify JSON format is enabled before going live
curl -s -o /dev/null -w '%{http_code}' 'http://searxng:8080/search?q=test&format=json'
# expect 200; 403 means 'formats' in settings.yml lacks json

Try / catch

result, err := searxngSearcher.Handle(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "unexpected status code: 403") {
        log.Printf("searxng JSON format disabled or forbidden; failing over: %v", err)
    }
    result, err = fallbackSearcher.Handle(ctx, req)
}

Prevention

When it happens

Trigger: SearxNG instance has JSON format disabled (returns 403 Forbidden); bot detection / limiter rejecting the PentAGI/1.0 User-Agent (429); wrong path producing 404; SearxNG overloaded (503); authentication plugin requiring a token (401).

Common situations: Default SearxNG settings where 'formats: [html]' doesn't include json — the classic cause of 403 for API consumers; searxng limiter enabled flagging datacenter traffic; rate limiting after heavy automated querying (429, but retryable).

Related errors


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