can1357/oh-my-pi · error · SearchProviderError
Exa MCP returned an error (falls back to `${message}` when p
Error message
Exa MCP returned an error (falls back to `${message}` when present) What it means
The MCP result was flagged isError=true (tool-level execution failure) and the result content contained no extractable text message. SearchProviderError is thrown with the generic fallback message 'Exa MCP returned an error' when no text content is found; if text is present, that text is used instead.
Source
Thrown at packages/coding-agent/src/web/search/providers/exa.ts:414
content?: Array<{ type: string; text?: string }>;
isError?: boolean;
};
error?: {
code: number;
message: string;
};
} | null;
if (!mcpResponse) {
throw new Error("Failed to parse MCP response");
}
if (mcpResponse.error) {
throw new Error(`MCP error: ${mcpResponse.error.message}`);
}
if (mcpResponse.result?.isError) {
const message = mcpResponse.result.content
?.find(item => item.type === "text" && typeof item.text === "string")
?.text?.trim();
throw new SearchProviderError("exa", message || "Exa MCP returned an error");
}
const responsePayload = normalizeExaMcpPayload(mcpResponse.result);
if (isSearchResponse(responsePayload)) {
return responsePayload as ExaSearchResponse;
}
const parsed = parseExaMcpTextPayload(responsePayload);
if (parsed) {
return parsed;
}
throw new Error("Exa MCP search returned unexpected response shape.");
}
/** Execute Exa web search */
export async function searchExa(params: ExaSearchParams): Promise<SearchResponse> {
// AuthStorage-backed key takes precedence (existing behavior); probe it once
// so the env-key and keyless-MCP fallbacks below stay intact, then drive theView on GitHub (pinned to 9690622007)
Solutions
- Retry the search — tool-level errors are often transient backend failures.
- Switch to the REST API path (EXA_API_KEY) for more descriptive error reporting.
- Use another search provider if Exa MCP errors persist.
- Log full MCP result content when debugging to see what was actually returned.
Defensive patterns
Strategy: fallback
Try / catch
try {
const res = await searchExa({ query });
} catch (e) {
if (e instanceof SearchProviderError && e.message === "Exa MCP returned an error") {
const res2 = await search({ provider: "brave", query }); // opaque tool failure: switch providers
} else throw e;
} Prevention
- Treat isError MCP results as transient and retry once before falling back
- Keep an alternative provider configured — this error can be opaque
- Prefer the REST path with an API key for richer error reporting
- Log full result.content to diagnose missing text payloads
When it happens
Trigger: The Exa MCP tool executed but reported failure via mcpResponse.result.isError with no { type: "text", text } item in result.content, or the text item was empty/whitespace after trim.
Common situations: Exa backend tool failure with a non-text error payload; protocol shape change removing the text content; upstream search failure reported as a tool error without details.
Related errors
- Exa MCP request failed (${response.status}): ${errorText}
- Failed to parse MCP response
- MCP error: ${mcpResponse.error.message}
- Exa MCP search returned unexpected response shape.
- Exa API error (${response.status}): ${errorText}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/92b66c0afbf14e4d.
Report an issue: GitHub.