Tencent/WeKnora · error
searxng returned status %d: %s
Error message
searxng returned status %d: %s
What it means
SearXNG responded with a non-200 HTTP status. The provider reads up to 1024 bytes of the body and includes it in the error so you can see the server's own message (HTML error pages, JSON error payloads, auth failures). Common statuses: 403 when JSON format is disabled, 401 when SearXNG requires auth, 429 for rate limiting, 502/503 for upstream engine failures.
Source
Thrown at internal/infrastructure/web_search/searxng.go:132
reqURL := p.baseURL + "/search?" + q.Encode()
logger.Infof(ctx, "[WebSearch][SearXNG] query=%q maxResults=%d url=%s", query, maxResults, p.baseURL)
req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Accept", "application/json")
req.Header.Set("User-Agent", "WeKnora/1.0")
resp, err := p.client.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to execute request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024))
return nil, fmt.Errorf("searxng returned status %d: %s", resp.StatusCode, string(body))
}
var data searxngResponse
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
p.lastUnresponsive = nil
return nil, fmt.Errorf("failed to decode SearXNG response (ensure JSON format is enabled in settings.yml): %w", err)
}
p.lastUnresponsive = data.UnresponsiveEngines
results := make([]*types.WebSearchResult, 0, maxResults)
for _, r := range data.Results {
if len(results) >= maxResults {
break
}
if r.URL == "" || r.Title == "" {
continue
}
item := &types.WebSearchResult{View on GitHub (pinned to 988cbb0330)
Solutions
- Read the embedded status/body in the error; if 403 with a 'format' message, enable JSON in SearXNG settings.yml (search: formats: [html, json]) and restart SearXNG
- If 429, add client-side rate limiting/backoff between Search calls
- If 401/403 from a proxy, configure the required auth (basic-auth credentials, token) for the provider or exempt the backend
- Check SearXNG logs for the failing request to confirm the server-side reason
Example fix
# before (searxng/settings.yml)
search:
formats:
- html
# after
search:
formats:
- html
- json Defensive patterns
Strategy: fallback
Validate before calling
// verify JSON format enabled before use
r, err := http.Get(baseURL + "/search?q=test&format=json")
if err != nil || r.StatusCode != http.StatusOK {
return fmt.Errorf("searxng JSON search not available (enable 'json' in search.formats)")
}
r.Body.Close() Try / catch
var httpErr interface{ HTTPStatus() int }; // or match on embedded status text
if strings.Contains(err.Error(), "status 403") {
// enable json format in searxng settings.yml
} else if strings.Contains(err.Error(), "status 429") {
// back off and retry later
} Prevention
- Enable 'json' in search.formats in SearXNG settings.yml at install time
- Smoke-test with curl '?format=json' after every SearXNG upgrade (upgrades can reset config)
- Add rate limiting on your side to avoid 429
- Monitor non-200 statuses and alert on 403 (config regression)
When it happens
Trigger: Any Search() call where the SearXNG instance returns e.g. 403 (Forbidden) because 'format: json' is not enabled in settings.yml, or 429 rate-limit responses under load.
Common situations: Fresh SearXNG install with default settings.yml (search.formats lacks json → 403); reverse proxy auth in front of SearXNG; too many concurrent queries causing 429.
Related errors
- create verification request failed: %w
- fetch feed %s: %w
- duckduckgo HTML returned status %d
- duckduckgo API returned status %d: %s
- failed to create Exa request: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/183529ab638aef63.
Report an issue: GitHub.