Tencent/WeKnora · error

failed to create Exa request: %w

Error message

failed to create Exa request: %w

What it means

Wraps errors from http.NewRequestWithContext when constructing the POST request to the Exa API. Given a constant http.MethodPost and a configured baseURL, failures indicate the configured base URL is not a valid URL or the context is invalid.

Source

Thrown at internal/infrastructure/web_search/exa.go:89

	}
	if maxResults > maxExaResults {
		maxResults = maxExaResults
	}

	bodyBytes, err := json.Marshal(exaSearchRequest{
		Query:      query,
		NumResults: maxResults,
		Contents: exaContents{
			Highlights: true,
			Text:       p.includeText,
		},
	})
	if err != nil {
		return nil, fmt.Errorf("failed to marshal Exa request: %w", err)
	}
	req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.baseURL, bytes.NewReader(bodyBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to create Exa request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("x-api-key", p.apiKey)

	logger.Infof(ctx, "[WebSearch][Exa] query=%q maxResults=%d url=%s", query, maxResults, p.baseURL)
	resp, err := p.client.Do(req)
	if err != nil {
		return nil, fmt.Errorf("failed to execute Exa request: %w", err)
	}
	defer resp.Body.Close()
	body, err := io.ReadAll(io.LimitReader(resp.Body, maxExaResponseBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to read Exa response: %w", err)
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices {
		logger.Warnf(ctx, "[WebSearch][Exa] API returned status %d: %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("exa API returned status %d: %s", resp.StatusCode, string(body))
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Verify p.baseURL is a valid absolute http(s) URL (log it on failure)
  2. Ensure the context passed to Search is valid and not pre-canceled
  3. Compare the configured base URL against the official Exa endpoint https://api.exa.ai/search
  4. Unwrap the %w error for the exact url.Parse failure

Example fix

// before
req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.baseURL, bytes.NewReader(bodyBytes))
// after
u, perr := url.Parse(p.baseURL)
if perr != nil || u.Scheme == "" || u.Host == "" {
    return nil, fmt.Errorf("invalid exa baseURL %q: %w", p.baseURL, perr)
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, p.baseURL, bytes.NewReader(bodyBytes))
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(cfg.ExaBaseURL)
if err != nil || u.Scheme == "" || u.Host == "" {
    return fmt.Errorf("invalid exa base URL %q", cfg.ExaBaseURL)
}
if err := ctx.Err(); err != nil {
    return err
}

Try / catch

results, err := provider.Search(ctx, query, 10, false)
if err != nil {
    if errors.Is(err, context.Canceled) {
        return nil, fmt.Errorf("search canceled: %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling Search when p.baseURL is malformed (bad config/default override) or ctx passed into Search is already canceled/invalid.

Common situations: A config override set baseURL to a garbage value, missing scheme in a custom endpoint, or an upstream canceled context propagated into Search.

Related errors


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