Tencent/WeKnora · error

exa API error: %s

Error message

exa API error: %s

What it means

Exa responded successfully (2xx, valid JSON) but the payload contains an application-level error in the error field of exaSearchResponse. The provider surfaces it verbatim so the developer can act on Exa's own error message (e.g. insufficient credits, invalid parameters).

Source

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

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

	var data exaSearchResponse
	if err := json.Unmarshal(body, &data); err != nil {
		return nil, fmt.Errorf("failed to unmarshal Exa response: %w", err)
	}
	if data.Error != "" {
		return nil, fmt.Errorf("exa API error: %s", data.Error)
	}

	results := make([]*types.WebSearchResult, 0, len(data.Results))
	for _, item := range data.Results {
		if len(results) >= maxResults {
			break
		}
		snippet := strings.TrimSpace(strings.Join(item.Highlights, "\n"))
		content := truncateExaText(strings.TrimSpace(item.Text), maxExaContentRunes)
		if snippet == "" {
			snippet = truncateExaText(content, 500)
		}
		result := &types.WebSearchResult{Title: item.Title, URL: item.URL, Snippet: snippet, Content: content, Source: "exa"}
		if includeDate && item.PublishedDate != "" {
			if publishedAt, err := time.Parse(time.RFC3339, item.PublishedDate); err == nil {
				result.PublishedAt = &publishedAt
			}
		}

View on GitHub (pinned to 988cbb0330)

Solutions

  1. Read the embedded Exa error message — it names the concrete problem (credits, key, policy).
  2. Check the Exa dashboard for credit balance and billing status.
  3. Confirm the API key's scopes/permissions cover the search endpoint.
  4. Adjust the query/parameters if the message indicates a policy or parameter violation.

Example fix

null
Defensive patterns

Strategy: try-catch

Validate before calling

if exaCreditsRemaining <= 0 { return errors.New("exa credits exhausted — skipping search") }

Try / catch

if err != nil && strings.HasPrefix(err.Error(), "exa API error:") {
    msg := strings.TrimPrefix(err.Error(), "exa API error: ")
    log.Warnf("exa rejected the search: %s", msg)
    return fallbackProvider.Search(ctx, q, n, false)
}

Prevention

When it happens

Trigger: A successful HTTP call where data.Error != "" — Exa reports a logical failure such as exhausted credits, an invalid API key accepted at transport level, or a disallowed query.

Common situations: Exa account out of credits or over quota; key valid but lacking permissions; query violating usage policies; billing lapsed.

Related errors


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