Tencent/WeKnora · error

failed to execute request: %w

Error message

failed to execute request: %w

What it means

The HTTP client failed to execute the Keenable search POST — p.client.Do(req) returned an error before any HTTP status was received. This wraps network-layer failures: DNS resolution, TCP connect, TLS handshake, timeouts, or context cancellation.

Source

Thrown at internal/infrastructure/web_search/keenable.go:100

	bodyBytes, err := json.Marshal(keenableSearchRequest{Query: query, Mode: "pro"})
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	req, err := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewReader(bodyBytes))
	if err != nil {
		return nil, fmt.Errorf("failed to create request: %w", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	req.Header.Set("X-Keenable-Title", keenableTitle)
	if p.apiKey != "" {
		req.Header.Set("X-API-Key", p.apiKey)
	}

	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 {
		respBody, _ := io.ReadAll(resp.Body)
		logger.Warnf(ctx, "[WebSearch][Keenable] API returned status %d: %s", resp.StatusCode, string(respBody))
		return nil, fmt.Errorf("keenable API returned status %d: %s", resp.StatusCode, string(respBody))
	}

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("failed to read response: %w", err)
	}

	var respData keenableSearchResponse
	if err := json.Unmarshal(respBody, &respData); err != nil {
		return nil, fmt.Errorf("failed to unmarshal response: %w", err)
	}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Inspect the wrapped error: connection refused/DNS means fix networking; context deadline means raise timeout or fix upstream latency.
  2. Verify network egress and DNS for the Keenable endpoint from the host running the code (curl the endpoint).
  3. Configure the proxy (params.ProxyURL) if the environment requires one.
  4. Add retry with backoff for transient network errors, respecting context cancellation.
  5. Check whether the configured base URL hostname resolves (typo in config).

Example fix

// before
resp, err := p.client.Do(req)
if err != nil { return nil, err }
// after (caller side)
results, err := keenable.Search(ctx, query, 10, false)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) {
        return nil, fmt.Errorf("keenable search timed out: %w", err)
    }
    return nil, fmt.Errorf("search unavailable, retry later: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

conn, err := net.DialTimeout("tcp", host+":443", 5*time.Second)
if err != nil { return fmt.Errorf("keenable endpoint unreachable before search: %w", err) }
conn.Close()

Try / catch

results, err := keenable.Search(ctx, q, n, false)
if err != nil && strings.Contains(err.Error(), "failed to execute request") {
    var netErr net.Error
    if errors.As(err, &netErr) && netErr.Timeout() {
        // retry once with backoff
    }
    return nil, fmt.Errorf("search network failure: %w", err)
}

Prevention

When it happens

Trigger: p.client.Do(req) errors — unreachable host, DNS failure, connection refused, TLS error, request timeout (client has a 30s-style timeout), or ctx cancelled/deadline exceeded mid-request.

Common situations: Keenable host unreachable from the deployment network; egress firewall blocks the endpoint; DNS misconfig; proxy required but not configured; context deadline exceeded because upstream took too long.

Related errors


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