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
- Read the embedded Exa error message — it names the concrete problem (credits, key, policy).
- Check the Exa dashboard for credit balance and billing status.
- Confirm the API key's scopes/permissions cover the search endpoint.
- 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
- Monitor Exa credit balance programmatically
- Set up billing alerts before quota exhaustion
- Route to a fallback provider when Exa reports app-level errors
- Surface the embedded Exa message to operators instead of swallowing it
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
- exa API returned status %d: %s
- failed to unmarshal Exa response: %w
- API key is required for Exa provider
- bing API returned status %d: %s
- duckduckgo API search failed: %w
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/38c88e84ceb104da.
Report an issue: GitHub.