Limits
The evaluations API enforces limits to keep the service stable under large or high-fan-out evaluations. They are set well above typical usage, so most evaluations never reach them.
This page lists every limit, what happens when you exceed it, and how to restructure an evaluation that does.
Payload size
| Limit | Value | Applies to |
|---|---|---|
| Request body size | 25 MB | Any single HTTP request |
| JSON field size | 1 MB | Each input, output, score value, and metadata object |
| Record size | 5 MB | One output record (all its generations, scores, and metadata combined) |
A request over the body limit is rejected with 413. An oversized field or record is rejected with 422 at validation. To store large blobs (documents, images, long transcripts), reference them by URL or ID instead of inlining them into a record.
How to fix each error:
413: the whole request is over the body limit. Lowerupload_batch_sizeto send fewer records per request.422on a JSON field: the 1 MB limit applies to each field of each record, not to a batch. A smaller batch doesn't help: shrink the oversized field itself.
Upload failures during a run
evaluation.run() and evaluation.optimize() upload results while they execute. The SDK handles upload failures in two ways:
- Invalid payload (
400,413, or422): the run stops at the first rejected upload instead of processing the remaining records, and is markedfailed. The error is raised as is, whatevermax_concurrency. - Any other failure (network errors,
5xx, and other4xxsuch as401,403,404,408,409, or429): the SDK retries the upload. A batch that still fails after 5 attempts fails the run. To change that number, set theMISTRAL_EVAL_UPLOAD_MAX_FAILED_ATTEMPTSenvironment variable (an integer of at least 1).
When an upload gets no answer (a timeout or a 504, for example), the server may already have stored the batch. The SDK re-sends the same batch unchanged and treats a 409 on that re-send as "already uploaded", so the run continues. Such a batch is never failed fast or counted against the retry limit.
Calls to the evaluations API use a timeout of at least 60 seconds. A longer Mistral(timeout_ms=...) still applies.
Fail-fast uploads and safe re-sends require SDK 0.9.0+.
Reading API errors
A failed API call raises ObservabilityAPIError with status_code, error_code, and details. For validation failures (422), the message names the offending fields, and details lists them as {"loc": [...], "msg": "..."} entries:
API request failed with status 422 (VALIDATION_ERROR): records.0.input: JSON field exceeds the maximum allowed size of 1000000 bytesThe submitted values are never included in the message, in details, or in the SDK debug logs.
from mistralai.evaluations import ObservabilityAPIError
try:
...
except ObservabilityAPIError as error:
print(error.status_code, error.error_code, error.details)A 5xx on an upload raises ObservabilityUnknownOutcomeError: the server may or may not have stored the data. It's a subclass of ObservabilityAPIError, so an except ObservabilityAPIError block also catches it.
Fan-out (per run)
An evaluation run expands into records × generations × evaluators score rows, so each factor is capped:
| Limit | Value | Applies to |
|---|---|---|
| Input records per run | 10,000 | Records uploaded to one run |
| Generations per run | 100,000 | Total generations across the whole run |
| Evaluators per run | 250 | evaluators + run_evaluators on a run |
num_generations | 1–100 | Generations produced per record |
num_scores (per evaluator) | 1–100 | Scores produced per evaluator per generation |
| Generations per output record | 100 | Generations attached to one record |
| Scores per generation | 500 | Scores attached to one generation |
Exceeding any of these returns a 422: either a "list too long" error or, for the per-run totals, a validation error naming the current count and the maximum.
Batch sizes
| Endpoint | Max items per call |
|---|---|
| Upload input records | 500 |
| Upload output records | 500 |
| Patch failed records | 500 |
| Upload run scores | 100 |
The SDK batches uploads for you, so you normally don't manage this. If you call the API directly, keep each request within these bounds.
String fields
| Field | Max length |
|---|---|
Score rationale | 5,000 characters (truncated by the SDK) |
Score error | 2,000 characters |
| Names (project, evaluation, run, evaluator) | 100 characters |
Optimization steer | 4,000 characters |
Reads and export
| Operation | Limit |
|---|---|
| Record export | 1,500,000 rows (truncated beyond, with a warning) |
| On-demand filtered statistics | 500,000 matching scores (rejected beyond: narrow the filter) |
| List pages (records, runs, and others) | 100 per page |
Too many evaluators
The evaluators-per-run cap (250) is the one most likely to affect an evaluation that scores many nodes or branches of a workflow graph.
A common anti-pattern is one evaluator per node. For example, an accuracy metric split into accuracy/MyWorkflow::node_1, accuracy/MyWorkflow::node_2, and so on. This attaches hundreds of evaluators to every record, even though each record only exercises a handful of nodes. Most of the resulting score rows are empty placeholders.
Instead, use one evaluator per metric, with the node as a dimension in the score's metadata (or in the score name). Emit a score only for the nodes a record actually touches. You keep the same per-node breakdown, stay well under the cap, and avoid creating thousands of empty scores.
Need a higher limit?
These values are server-side defaults that protect shared infrastructure. If your use case needs a higher limit, contact your Mistral representative instead of working around it.
Next steps
- API reference:
evaluation.run()parameters, includingupload_batch_size. - Workflow evaluation plugin limits: the extra limits that apply when an evaluation runs inside a workflow.