> For clean Markdown of any page, append `.md` to the page URL. > For a complete documentation index, see https://docs.sarvam.ai/llms.txt. > For full documentation content in one file, see https://docs.sarvam.ai/llms-full.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.sarvam.ai/_mcp/server. # Error handling on SageMaker > How every self-hosted Sarvam endpoint reports errors on SageMaker: the 424 collapse through InvokeEndpoint, the shared error envelope, and the overload back-off rule for Saaras v3, Bulbul v3, and Sarvam Vision. Every Sarvam model container on SageMaker uses the same error contract. Read this once, then see the per-model references — [Speech-to-Text](/api/self-hosted/sagemaker/api-saaras#errors), [Text-to-Speech](/api/self-hosted/sagemaker/api-bulbul#errors), and [Sarvam Vision](/api/self-hosted/sagemaker/api-vision#errors) — for the model-specific bodies. ## Every non-2xx is delivered as HTTP 424 Through `sagemaker-runtime:InvokeEndpoint`, any error the container returns is collapsed by boto3 into a **`ModelError` (HTTP 424)**. The container's real status is in **`OriginalStatusCode`**, its JSON body in **`OriginalMessage`**, and its `Retry-After` **header is dropped** — so retry hints ride in the **body** as `retry_after`. > **Warning** > > Branch on `OriginalStatusCode` + `error.code`, **never** on the HTTP status (it is always `424`). ```python from botocore.exceptions import ClientError import json try: r = client.invoke_endpoint(EndpointName=EP, ContentType=ct, Body=body) except ClientError as e: status = e.response["OriginalStatusCode"] # 400 / 429 / 503 / … err = json.loads(e.response["OriginalMessage"])["error"] if status == 400: raise # bad request — fix it, never retry elif err["code"] == "service_overloaded": backoff(err.get("retry_after", 1)) # 429 or 503 — back off with jitter else: retry_once() # 5xx — retry once, then report err["request_id"] ``` ## Error envelope Every error body is JSON with the same shape: ```json { "error": { "code": "…", "message": "…", "request_id": "…" } } ``` Optional fields extend it: `detail_code` (a specific reason), `retryable` (bool), and `retry_after` (seconds). **Sarvam Vision** always carries `detail_code` and `retryable`. ## Overload (backpressure) sheds immediately — it does not queue At capacity, the container rejects excess work at once rather than queueing it, using `error.code = "service_overloaded"` with a body `retry_after`: | Model | `OriginalStatusCode` | `error.code` | Retry | | -------------------------- | :------------------: | -------------------- | ------------------------------------ | | Speech-to-Text (Saaras v3) | `429` | `service_overloaded` | back off; body `retry_after` seconds | | Text-to-Speech (Bulbul v3) | `503` | `service_overloaded` | back off; body `retry_after` seconds | | Sarvam Vision (OCR) | `503` | `service_overloaded` | back off; body `retry_after` seconds | > **Note** > > **Client rule:** treat **`429` or `503` with `code: "service_overloaded"`** as "retry after `retry_after` seconds, with jitter." Never retry a `400` — fix the request instead. > How every self-hosted Sarvam endpoint reports errors on SageMaker: the 424 collapse through InvokeEndpoint, the shared error envelope, and the overload back-off rule for Saaras v3, Bulbul v3, and Sarvam Vision.