Tencent/WeKnora · error

failed to decode SearXNG response (ensure JSON format is ena

Error message

failed to decode SearXNG response (ensure JSON format is enabled in settings.yml): %w

What it means

The HTTP response was status 200 but its body could not be decoded into the expected searxngResponse JSON shape. SearXNG by default returns HTML; JSON output must be explicitly enabled via the 'json' format in settings.yml, so a 200 HTML page (the search UI) fails json.Decode. The message explicitly hints at this configuration.

Source

Thrown at internal/infrastructure/web_search/searxng.go:138

	}
	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{
			Title:   r.Title,
			URL:     r.URL,
			Snippet: r.Content,
			Source:  "searxng",
		}
		if includeDate && r.PublishedDate != "" {

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Edit SearXNG settings.yml to add 'json' under search: formats: and restart the container
  2. curl '<baseURL>/search?q=test&format=json' to confirm raw JSON comes back before integrating
  3. Verify the baseURL points at the SearXNG root, not an HTML page or different service behind the same proxy
  4. Inspect the actual body (log first 1KB on decode failure) to identify HTML/interstitial content

Example fix

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

Strategy: validation

Validate before calling

// verify the endpoint returns JSON, not HTML
r, _ := http.Get(baseURL + "/search?q=test&format=json")
b, _ := io.ReadAll(io.LimitReader(r.Body, 512))
r.Body.Close()
if !json.Valid(b) && !strings.HasPrefix(strings.TrimSpace(string(b)), "{") {
    return fmt.Errorf("searxng did not return JSON; enable 'json' format in settings.yml")
}

Prevention

When it happens

Trigger: Search() receiving a 200 response whose body is HTML (JSON format disabled), a proxy/interstitial page, or truncated/invalid JSON.

Common situations: Default SearXNG settings.yml without 'json' in search.formats; a reverse proxy or WAF returning an HTML challenge page with 200; misconfigured base URL hitting a different app that returns 200 HTML.

Understand the failure class

Related errors


AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02). Data as JSON: /api/errors/f0b17050700aa514. Report an issue: GitHub.