fix(mistralai): standardize API error handling - #2518
rosetta-livekit-bot[bot] wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 85f7dad The changes in this PR will be included in the next version bump. This PR includes changesets to release 39 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
| return new APITimeoutError({ message: error.message, options: { retryable } }); | ||
| } | ||
|
|
||
| if (error instanceof SDKError || error instanceof HTTPValidationError) { |
There was a problem hiding this comment.
🟡 Malformed validation responses trigger retries
A malformed 422 response makes mistralAPIError ignore ResponseValidationError. Callers retry it as a connection failure and lose its status, body, and request ID.
Learn more
The Mistral SDK wraps a response that fails its expected schema in ResponseValidationError. That class extends MistralError and retains statusCode, headers, and body, but it is neither SDKError nor HTTPValidationError. The LLM and TTS endpoints can produce it when a 422 body is valid JSON but does not match HTTPValidationError; the SDK's response matcher constructs it before this helper runs. The helper returns undefined, so each caller falls back to a retryable APIConnectionError.
Example: Mistral returns HTTP 422 with body {"unexpected":"shape"}. The SDK raises ResponseValidationError with status 422. The plugin retries it as a connection error instead of returning a non-retryable APIStatusError containing the provider details.
Recommended fix: Match the SDK's MistralError base class, or explicitly include ResponseValidationError, and copy the same status, request ID, and body fields into APIStatusError. Add a malformed-422 test for an endpoint using the validation matcher.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Ports livekit/agents#7308 to standardize Mistral API error handling across LLM, STT, and TTS.
APIStatusError.x-request-idvalues.APITimeoutError.Validation
pnpm test plugins/mistralai(4 passed, 3 provider-key tests skipped)pnpm test agents(2,710 passed, 5 skipped; 3 unrelated environment-specific failures inagents/src/telemetry/loop_monitor.test.tsbecause this runtime reports process CPU scope instead of thread CPU scope)pnpm build(40/40 workspace builds passed)pnpm --filter @livekit/agents lint(passed with existing warnings)pnpm --filter @livekit/agents-plugin-mistralai lintpnpm --filter @livekit/agents typecheckpnpm --filter @livekit/agents-plugin-mistralai exec tsc --noEmitpnpm format:checkRepository-wide
pnpm lintremains blocked by an unrelated existing@typescript-eslint/no-misused-promiseserror inplugins/openai/src/ws/llm.ts:127. API Extractor also reports unrelated stale base-branch API entries (SpeechStream.terminalErrorand typed-emitter imports); this PR includes only the intentionalAPIError.bodyreport update.Source diff coverage
Source diff coverage
livekit-plugins/livekit-plugins-mistralai/livekit/plugins/mistralai/llm.pytoplugins/mistralai/src/llm.tsand the shared target-specific translator inplugins/mistralai/src/errors.ts. Uses the TypeScript SDK error classes, preserves status/body/request ID, maps SDK timeouts, and retains stream retryability after output.livekit-plugins/livekit-plugins-mistralai/livekit/plugins/mistralai/stt.pytoplugins/mistralai/src/stt.tsandplugins/mistralai/src/errors.ts. Applies the same SDK translation to batch and realtime STT; additionally maps the TypeScript SDK realtime handshake timeout wrapper because it has no Python counterpart class.livekit-plugins/livekit-plugins-mistralai/livekit/plugins/mistralai/tts.pytoplugins/mistralai/src/tts.tsandplugins/mistralai/src/errors.ts. Applies standardized status, timeout, request ID, and raw-body handling.tests/test_plugin_mistralai_llm.pyinto the existingplugins/mistralai/src/llm.test.ts. Ports exactly the source scenarios for HTTP 400, HTTP 422 detail preservation, and failure after the first streamed chunk; assertions use the target framework error-event contract.agents/src/_exceptions.tsandagents/etc/agents.api.mdwidenAPIError.bodyto accept raw strings, which is required to preserve the Mistral SDK body exactly as the source change does.Ported from livekit/agents#7308
Original PR description
Summary
Standardize Mistral error handling across LLM, STT, and TTS while preserving provider error details and retry semantics.
Motivation
With an invalid LLM model such as
foo, Mistral returns HTTP 400 with error code 3003.The LLM plugin previously handled Mistral's
SDKErroras a generic exception, turning this non-retryable API response into a retryableAPIConnectionError. One user turn therefore produced four misleadingConnection errorevents, theinitial request plus three retries.
Changes
SDKErrorandHTTPValidationErrorintoAPIStatusErroracross LLM, STT, and TTS.x-request-id.asyncio/httpxtimeouts intoAPITimeoutError.Ordinary 4xx responses are now non-retryable, while transient statuses continue to follow
APIConnectOptions.Tests
APIStatusError.