vxcontrol/pentagi · error · Fatal

failed to create request: %w

Error message

failed to create request: %w

What it means

http.NewRequestWithContext failed while constructing the GET request to the SearxNG endpoint. This wraps Go's standard library error and is classified Fatal. With a URL already validated by url.Parse earlier, this is nearly impossible to hit in practice — it can only occur if the serialized URL (after appending /search and query params) becomes invalid, e.g. contains a NUL byte.

Source

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

	if maxResults > 0 {
		params.Add("limit", strconv.Itoa(maxResults))
	} else {
		params.Add("limit", "10")
	}

	apiURL.RawQuery = params.Encode()

	client, err := system.GetHTTPClient(s.cfg)
	if err != nil {
		return "", Fatal(fmt.Errorf("failed to create http client: %w", err))
	}

	client.Timeout = s.timeout()

	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)

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the final apiURL.String() value in logs for control characters and sanitize the SEARXNG_URL env
  2. Strip control characters from the configured URL before parsing (strings.Map with unicode.IsPrint filter)
  3. Fix the source of the corrupted value in .env, docker-compose.yml, or secrets injection
  4. This is Fatal — no retry will occur; restart with corrected configuration
  5. If persistent, add a startup-time validation of SEARXNG_URL so misconfiguration fails fast at boot

Example fix

// before
req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiURL.String(), nil)
// after
cleanURL := strings.Map(func(r rune) rune {
    if r == 0 || !unicode.IsPrint(r) { return -1 }
    return r
}, apiURL.String())
req, err := http.NewRequestWithContext(ctx, http.MethodGet, cleanURL, nil)
Defensive patterns

Strategy: validation

Validate before calling

// sanitize and validate before request construction
u := strings.Map(func(r rune) rune { if r == 0 || !unicode.IsPrint(r) { return -1 }; return r }, baseURL)
if _, err := url.ParseRequestURI(u); err != nil {
    return fmt.Errorf("unusable searxng URL %q: %w", u, err)
}

Prevention

When it happens

Trigger: The base URL string contains a NUL byte (\x00) or other control character that url.Parse accepted but NewRequestWithContext rejects via url.ParseRequestURI; ctx already canceled does NOT trigger this (that fails at client.Do).

Common situations: Env var polluted with a NUL byte from bad shell templating or binary-joined config strings; pathological SEARXNG_URL values surviving url.Parse.

Related errors


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