vxcontrol/pentagi · error · Fatal

invalid searxng base URL: %w

Error message

invalid searxng base URL: %w

What it means

The SearxNG searcher parses the configured base URL (cfg.SearxngURL) with net/url.Parse before appending /search and issuing the query. If the URL cannot be parsed, the search aborts with a Fatal error (no retry). Note that Go's url.Parse is very permissive and almost never errors, so hitting this usually means control characters or a severely malformed value in the configuration.

Source

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

			langfuse.WithEventMetadata(langfuse.Metadata{
				"engine":      "searxng",
				"query":       req.Query,
				"max_results": req.MaxResults,
				"error":       err.Error(),
			}),
		)

		obs.LogErrorOrCancel(logger, err, "failed to search in searxng")
		return "", err
	}

	return result, nil
}

func (s *searxng) search(ctx context.Context, query string, maxResults int) (string, error) {
	apiURL, err := url.Parse(s.baseURL())
	if err != nil {
		return "", Fatal(fmt.Errorf("invalid searxng base URL: %w", err))
	}

	if !strings.HasSuffix(apiURL.Path, "/search") {
		apiURL.Path = strings.TrimSuffix(apiURL.Path, "/") + "/search"
	}

	params := url.Values{}
	params.Add("q", query)
	params.Add("format", "json")
	params.Add("language", s.language())
	params.Add("categories", s.categories())
	params.Add("safesearch", s.safeSearch())

	if timeRange := s.timeRange(); timeRange != "" {
		params.Add("time_range", timeRange)
	}

	if maxResults > 0 {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Print/verify the SEARXNG_URL env value and fix malformed characters (use a plain URL like http://searxng:8080)
  2. Validate the URL manually: url.Parse('your-value') in a scratch Go program to reproduce the exact parse error
  3. Check .env / docker-compose.yml for line-continuation or quoting issues that corrupt the value
  4. Restart the container after fixing the env so the config is re-read
  5. Note the error is Fatal — the orchestrator will fall back to other engines only if a fallback chain is configured

Example fix

// before (.env)
SEARXNG_URL=http://searxng:8080/search
   
# after (.env)
SEARXNG_URL=http://searxng:8080
Defensive patterns

Strategy: validation

Validate before calling

// validate at startup
srv, err := url.Parse(os.Getenv("SEARXNG_URL"))
if err != nil || srv.Scheme == "" || srv.Host == "" {
    log.Fatalf("invalid SEARXNG_URL %q: %v", os.Getenv("SEARXNG_URL"), err)
}

Type guard

func validHTTPURL(raw string) bool {
    u, err := url.Parse(raw)
    return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
}

Prevention

When it happens

Trigger: SEARXNG_URL contains invalid characters (spaces, raw control characters, unescaped non-ASCII in unusual positions) or a corrupted value from env interpolation, e.g. SEARXNG_URL="http://searxng:8080\n" or a value containing an unescaped newline.

Common situations: Misconfigured docker-compose env with accidental whitespace/newline in SEARXNG_URL; secrets templating tools injecting malformed values; copy-paste of a URL with invisible Unicode characters.

Related errors


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