Tencent/WeKnora · error

keenable API returned status %d: %s

Error message

keenable API returned status %d: %s

What it means

This error is returned by KeenableProvider.Search when the Keenable web search API responds with an HTTP status other than 200 OK. The provider reads the response body and embeds both the status code and the raw body in the message, so the text after the status tells you exactly what the API complained about (e.g. 401 unauthorized, 429 rate limit, 500 server error). It is a wrapper around a remote-API rejection, not a local bug.

Source

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

		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)
	}

	results := make([]*types.WebSearchResult, 0, len(respData.Results))
	for _, item := range respData.Results {
		if maxResults > 0 && len(results) >= maxResults {
			break
		}
		// Keenable returns both a short "description" and a longer "snippet"

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Read the status code and body embedded in the error message to identify the root cause (401/403 = credentials, 429 = quota, 5xx = server side).
  2. Verify the Keenable API key configured for the provider is valid and active; regenerate it if it was rotated.
  3. Check your Keenable account quota/billing if the status is 429, and back off before retrying.
  4. If the status is 5xx, retry later or check Keenable's status page / inspect the response body for an upstream incident.
  5. Inspect the raw response body in the error for a provider-specific error code or HTML from an intercepting proxy.

Example fix

// before: no handling of non-200 detail
results, err := provider.Search(ctx, query, 10, false)
if err != nil { return err }

// after: log status and body, branch on status class
results, err := provider.Search(ctx, query, 10, false)
if err != nil {
    var statusErr string = err.Error()
    if strings.Contains(statusErr, "401") || strings.Contains(statusErr, "403") {
        return fmt.Errorf("keenable credentials invalid, refresh API key: %w", err)
    }
    return fmt.Errorf("search failed: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if strings.TrimSpace(cfg.KeenableAPIKey) == "" {
    return fmt.Errorf("keenable API key must be configured before searching")
}

Try / catch

results, err := provider.Search(ctx, query, 10, false)
if err != nil {
    if strings.Contains(err.Error(), "returned status 4") {
        // client-side: bad key or quota — alert, don't retry blindly
        return nil, fmt.Errorf("keenable rejected request: %w", err)
    }
    if strings.Contains(err.Error(), "returned status 5") {
        // server-side: safe to retry with backoff
        return retryWithBackoff(ctx, query)
    }
    return nil, err
}

Prevention

When it happens

Trigger: KeenableProvider.Search (internal/infrastructure/web_search/keenable.go:107) receives an HTTP response whose StatusCode != http.StatusOK — e.g. expired/invalid API key producing 401, exceeded quota producing 429, or upstream 5xx outages.

Common situations: Misconfigured or rotated-out API key in provider parameters; exhausted Keenable quota or billing lapse; Keenable service incident returning 5xx; firewall/proxy intercepting the request and returning a non-200 HTML page.

Related errors


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