vxcontrol/pentagi · error · FatalError

failed to create request: %w

Error message

failed to create request: %w

What it means

`http.NewRequestWithContext` fails while constructing the POST to the Perplexity API, wrapped as Fatal at backend/pkg/tools/searchers/perplexity.go:174. With `perplexityURL` being a compile-time constant this essentially only fires if the URL constant/variable is invalid (bad method, unparsable URL, nil body on custom builds) or ctx is already built with an invalid state.

Source

Thrown at backend/pkg/tools/searchers/perplexity.go:174

		SearchContextSize:      p.contextSize(),
		MaxTokens:              p.maxTokens(),
		Temperature:            p.temperature(),
		TopP:                   p.topP(),
		ReturnImages:           false,
		ReturnRelatedQuestions: false,
		Stream:                 false,
	}

	// Serializing the request
	reqBody, err := json.Marshal(reqPayload)
	if err != nil {
		return "", Fatal(fmt.Errorf("failed to marshal request body: %w", err))
	}

	// Creating HTTP request
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, perplexityURL, bytes.NewBuffer(reqBody))
	if err != nil {
		return "", Fatal(fmt.Errorf("failed to create request: %w", err))
	}

	// Setting request headers
	req.Header.Set("Authorization", "Bearer "+p.apiKey())
	req.Header.Set("Content-Type", "application/json")

	// Sending the request
	resp, err := client.Do(req)
	if err != nil {
		return "", Retryable(fmt.Errorf("failed to send request: %w", err), 0)
	}
	defer resp.Body.Close()

	// Handling the response. handleErrorResponse keeps the per-status message; the
	// retryable/fatal classification is decided here from the status code.
	if resp.StatusCode != http.StatusOK {
		baseErr := p.handleErrorResponse(resp.StatusCode)
		if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the wrapped error — NewRequest errors name the invalid URL component
  2. If perplexityURL was made configurable, validate it with url.Parse and require http/https scheme at startup
  3. Trim spaces/newlines from any configured endpoint URL
  4. Nothing to fix at runtime on stock builds: verify you are on an unmodified binary

Example fix

// before
endpoint := os.Getenv("PERPLEXITY_URL") // may be " https://x " or schemeless
// after
endpoint := strings.TrimSpace(os.Getenv("PERPLEXITY_URL"))
if u, err := url.Parse(endpoint); err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    endpoint = perplexityURL // fall back to official API
}
Defensive patterns

Strategy: validation

Validate before calling

// validate the endpoint before constructing requests
u, err := url.Parse(endpoint)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
    endpoint = perplexityURL // fall back to official constant
}

Try / catch

_, err := engine.Handle(ctx, req)
if err != nil && searchers.IsFatal(err) && strings.Contains(err.Error(), "failed to create request") {
    // URL/method construction problem: check endpoint override, do not retry
}

Prevention

When it happens

Trigger: `search` is called and `http.NewRequestWithContext(ctx, http.MethodPost, perplexityURL, ...)` returns an error — practically only when perplexityURL has been overridden to a malformed custom endpoint URL (invalid characters, missing scheme, control characters).

Common situations: Custom fork or patched build redirecting Perplexity traffic to a self-hosted gateway with a bad URL; misinterpreted build tag swapping the constant; URL copied with trailing spaces/newline.

Understand the failure class

Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.

Related errors


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