{"record":{"id":"991fb85f14a03040","repo":"vxcontrol/pentagi","slug":"unexpected-status-code-d-991fb8","errorCode":null,"errorMessage":"unexpected status code: %d","messagePattern":"unexpected status code: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/searchers/searxng.go","lineNumber":134,"sourceCode":"\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL.String(), nil)\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to create request: %w\", err))\n\t}\n\n\treq.Header.Set(\"User-Agent\", \"PentAGI/1.0\")\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", Retryable(fmt.Errorf(\"failed to do request: %w\", err), 0)\n\t}\n\tdefer resp.Body.Close()\n\n\treturn s.parseHTTPResponse(resp, query)\n}\n\nfunc (s *searxng) parseHTTPResponse(resp *http.Response, query string) (string, error) {\n\tif resp.StatusCode != http.StatusOK {\n\t\terr := fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t\tif resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {\n\t\t\treturn \"\", Retryable(err, 0)\n\t\t}\n\t\treturn \"\", Fatal(err)\n\t}\n\n\tvar searxngResponse SearxngResponse\n\tif err := json.NewDecoder(resp.Body).Decode(&searxngResponse); err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to decode response body: %w\", err))\n\t}\n\n\treturn s.formatResults(searxngResponse.Results, query), nil\n}\n\nfunc (s *searxng) formatResults(results []SearxngResult, query string) string {\n\tif len(results) == 0 {\n\t\treturn fmt.Sprintf(\"# No Results Found\\n\\nNo results were found for query: %s\", query)\n\t}","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/searxng.go#L116-L152","documentation":"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).","triggerScenarios":"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).","commonSituations":"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).","solutions":["Enable JSON output in SearxNG settings.yml: under search: add 'formats: [html, json]' and restart the instance (fixes 403)","If 429: check the limiter plugin config or raise rate limits; this error is Retryable so backoff may suffice","If 404: confirm the instance serves /search at the configured SEARXNG_URL path (trailing path handled automatically, but reverse-proxy rewrites can break it)","If 401: configure the auth token expected by the instance or remove the auth plugin","Check SearxNG container logs for the request to correlate the rejected status"],"exampleFix":"// before (searxng settings.yml)\nsearch:\n  formats:\n    - html\n// after (searxng settings.yml)\nsearch:\n  formats:\n    - html\n    - json\n","handlingStrategy":"fallback","validationCode":"// verify JSON format is enabled before going live\ncurl -s -o /dev/null -w '%{http_code}' 'http://searxng:8080/search?q=test&format=json'\n# expect 200; 403 means 'formats' in settings.yml lacks json","typeGuard":null,"tryCatchPattern":"result, err := searxngSearcher.Handle(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected status code: 403\") {\n        log.Printf(\"searxng JSON format disabled or forbidden; failing over: %v\", err)\n    }\n    result, err = fallbackSearcher.Handle(ctx, req)\n}","preventionTips":["Enable json in search.formats of SearxNG settings.yml — the #1 cause of 403 for API consumers","Disable or tune the limiter/bot-detection plugin for known datacenter clients, or expect 429s","Keep alternative engines in the fallback chain since 4xx here is Fatal (non-retryable)","Monitor status codes per engine to distinguish limiter 429s (retryable) from config 403/404 (fatal)"],"tags":["http-status","searxng","http","configuration"],"backgroundTag":"unexpected-http-status","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}