Platform Limitations
On this page
Know the Limits
The Mistral Workflows platform is in Public Preview (as of April 2026). Like any orchestration system, it imposes technical constraints that you must understand to design robust workflows. These limits aren’t just documentation footnotes; they show up in production, often late in the game, as serialization errors or workflows terminated unexpectedly with no warning in your code. Knowing them upfront changes how you structure your processing logic.
The table below summarizes the key constraints and the concrete consequence of exceeding each one.
| Limitation | Value | Consequence if exceeded |
|---|---|---|
| Delay between activities | 2 seconds | Unavoidable latency between each activity call |
| Input/output per invocation | 2 MB | Serialization error, workflow fails |
| Events per execution | 51,200 | Workflow forcibly terminated |
| Total size per execution | 50 MB | Workflow forcibly terminated |
| Default timeout | 1 hour | Workflow cancelled (configurable up to 7 days) |
| Maximum timeout | 7 days | Workflow automatically cancelled |
| I/O in workflows | Forbidden | Non-determinism error during replay |
Two Seconds Between Each Activity
The platform enforces a minimum 2-second delay between activity calls. This latency isn’t a teething problem; it’s inherent to the orchestration architecture, which persists every event before proceeding. It’s the price of durability.
The impact is easy to calculate and often surprising. A workflow chaining ten sequential activities consumes at least twenty seconds of orchestration time, regardless of how long the activities themselves take. If each activity runs in fifty milliseconds, you’ve designed a half-second job that takes twenty seconds to return a result.
The workaround is to bundle operations that don’t need to be separate into a single activity. Compare these two versions of the same NLP pipeline.
# SUBOPTIMAL: 3 activities = 6 seconds of orchestration latency
@workflows.workflow.define(name="pipeline_lent")
class SlowPipeline:
@workflows.workflow.entrypoint
async def run(self, text: str) -> dict:
tokens = await tokenize(text)
embeddings = await calculate_embeddings(tokens)
clusters = await cluster(embeddings)
return clusters
# OPTIMIZED: 1 activity = 2 seconds of orchestration latency
@workflows.activity()
async def complete_nlp_processing(text: str) -> dict:
tokens = tokenize_local(text)
embeddings = calculate_embeddings_local(tokens)
clusters = cluster_local(embeddings)
return {"clusters": clusters}
@workflows.workflow.define(name="pipeline_rapide")
class FastPipeline:
@workflows.workflow.entrypoint
async def run(self, text: str) -> dict:
return await complete_nlp_processing(text)
The rule for splitting becomes simple: create a separate activity only if you need the persistence guarantee between two operations. If two operations can fail together without causing issues—like local tokenization and embedding calculation chained in memory—bundle them.
Two Megabytes Per Invocation
Each activity call is limited to 2 MB for input and 2 MB for output, based on the serialized JSON representation of the data. A report PDF, a set of images, or a large CSV export will easily exceed this, causing the workflow to fail with a serialization error.
The solution is one sentence: pass references, never payloads. The activity downloads the data from external storage, processes it locally (where it’s limited only by the worker’s memory), and returns the result URL.
@workflows.activity()
async def traiter_gros_fichier(fichier_url: str) -> dict:
"""Download, process, and re-upload the file.
Only URLs pass through the workflow."""
async with httpx.AsyncClient() as client:
# Download from S3/GCS
response = await client.get(fichier_url)
contenu = response.content # Could be 100 MB
# Process the file
resultat = traiter(contenu)
# Upload the result
await client.put(
"https://storage.example.com/résultats/output.json",
content=resultat
)
return {"url_resultat": "https://storage.example.com/résultats/output.json"}
The Event and Volume Budget
Each execution is capped at 51,200 events. The platform generates an event for every activity start, every activity completion, every signal received, and every timer triggered. In practice, an activity call costs about two to three events once metadata is counted, putting a hundred-activity workflow around 250 to 300 events. In other words, the cap allows fifteen to twenty thousand activity calls per execution: far beyond what most use cases require.
You’ll only hit this limit with bulk processing—for example, iterating through fifty thousand documents in a single execution. The continuation pattern, detailed in the next lesson, solves this: the workflow processes a batch, then launches a new workflow for the next batch, resetting the event counter.
The second bound concerns volume: the cumulative size of all events in an execution must not exceed 50 MB. This fills up faster if your activities return rich objects, since every result is written to the log. The same reflex applies—return an identifier rather than a full structure, store intermediate results in an external service, paginate processing in batches—and it suffices in the vast majority of cases.
No I/O in the Workflow
The last line of the table isn’t a sizing limit but a design rule, already covered under determinism. Workflow code must contain no input/output operations: no network calls (httpx, aiohttp, requests), no file reading or writing (open, aiofiles), no database access, and no reading of environment variables to steer branching. All these operations live in activities, whose results are logged and therefore replayable identically.
Key Takeaways
- 2 seconds minimum latency between each activity—bundle related operations
- 2 MB maximum per activity input/output—use external storage for large data
- 51,200 events and 50 MB maximum per execution—use the continuation pattern for very long workflows
- No I/O in workflow code—everything goes in activities
- These limitations stem from the underlying Temporal architecture and the Public Preview status