Skip to content

Limits

Every run needs brakes. These are the ones you control, and the fixed limits worth knowing.

WhereSettingWhat happens
Interactionduration.warn = "00:02:00"the agents are told time is running short
Interactionduration.max = "00:04:00"the run stops with Error (“Interaction timed out”)
One rundurationWarningOverride, durationAutoTerminationOverride in the start requestoverrides the two above for that run
Appduration.max in the app’s .mtrthe app stops
CapsulemaxDuration (default 10 minutes), and per command maxDuration (default 300 seconds)the capsule or command stops
Code pipelinedurationAutoTermination, and per-step limitsthe step or run stops

Durations are written "hh:mm:ss", so five minutes is "00:05:00". An interaction with no duration.max has no time limit. Time spent waiting for a person doesn’t count.

A run left waiting for a person’s message for more than three days is closed as Finished. It isn’t lost: a message sent to it later opens it again where it left off.

See it in tutorial 14, whose research run is warned at two minutes and stopped at four. Child runs started as sub-interactions never run past the time their parent has left.

An agent in an interaction can make at most 10 rounds of tool calls per turn. After that its tools are withheld for the rest of the turn, and it must answer with what it has. Change it with context = { maxToolCallLoops = 20 }, or 0 for no limit.

Long conversations and big tool results can outgrow a model’s context window. context controls what Maitento does about it:

SettingValuesDefault
modeAutomatic, Aggressive, None, or FailOnOverflowAutomatic
toolResultTrimming.modeNever, OnOverflow, AfterCycles or Both: replace old tool results with a placeholder or digestOnOverflow
compaction.typeNone, SameAgent or StandaloneAgent: summarise older parts of the conversationNone
responseMaxTokensthe most the model may write in one reply32,000

The defaults are the same however the interaction was made: deployed from a .mtr file with no context block, or created through the API without contextSettings. Automatic, which shortens the oldest part of the conversation when it no longer fits, is right for almost everything. Choose FailOnOverflow for a run that must end with an error rather than lose part of its conversation.

SettingDefaultMaximum
Managed limits.maxDispatches30200
Round-robin rules.noActionLoops.maxno limit
Sub-interactions swarm.maxDepth / maxConcurrent / maxTotal1 / 5 / 204 / 20 / 100

Team limits are soft: the run carries on. A manager that has used its dispatches is told so and finishes with what it has, and an agent that can’t start another sub-interaction is told why. Only time is hard: at duration.max the run stops with Error. See them in tutorial 19, which runs out of dispatches on purpose, and tutorial 18.

What your plan includes, and how work is paid for, is in Plans and billing. Your plan also decides what you can start. A start it refuses answers 400 with one of these codes, and creates nothing:

CodeWhyWhat to do
api:billing:premium-not-includedYour plan doesn’t include sandboxes (capsules) or code pipelinesupgrade
api:billing:allowance-usedon a plan without top-ups, this kind of work has used its allowance for the billing periodwait for the next period, or upgrade
api:billing:out-of-credityour balance can’t pay for more work, so nothing new starts anywhere in your tenanttop up, or upgrade
api:billing:tenant-lockedyour tenant has been paused by Maitento, so nothing new starts until it’s unlocked; work already running carries oncontact Maitento support

Your allowance is used first, then your balance. A plan with top-ups runs past its allowance on its balance, and is refused only when the balance is spent. The same applies to child runs: a run that starts another is refused in the same way, and the refusal is what its start returns.

When your tenant runs out of credit, the work it already has going is stopped too: queued, running and waiting runs end as Killed. On a plan without top-ups, only the work on the allowance that ran out is stopped.

Saving a file, or writing to a file system through the API, is checked the same way:

CodeWhy
api:billing:storage-cap-reachedthe write would take you over your plan’s storage, and your plan can’t pay for more
api:billing:out-of-credityou’re out of credit, or over your storage with nothing in your balance to pay for it

An agent’s web search or fetch that your plan can’t pay for comes back as a failed result with the error code out_of_credit, allowance_used or tenant_locked, like any other web tool failure, so the agent can carry on without it.

Your plan also limits how many knowledge bases (temporary ones included) and file systems you can hold (api:partition:limit-reached, api:file-system:limit-reached), as it does credentials and stacks. A lower limit never deletes anything: it only stops you creating more until you’re under it.

The error-code reference lists every plan and billing code, including the ones for buying and changing a plan.

Your plan includes lanes for each kind of work: standard (interactions and apps together), sandboxes (capsules) and code pipelines. A lane is room for one run at a time.

When all your lanes of one kind are in use, a new run isn’t refused. It waits in status New, and starts as soon as one of your runs of that kind finishes, or stops to wait for a person, an approval or the runs it started. Your runs take their turn in the order you started them. A run that carries on after waiting (a reply, an approval, its child runs finishing) takes a lane again, and waits for one like a new run.

A run started by an app doesn’t wait for a lane. The app is still running while it waits for its child, so the child would otherwise be waiting for the app. The child still uses a lane while it runs.

When the platform is busy, runs on higher plans start first, and tenants on the same plan take turns. Free work runs when no paid work is waiting, with a share kept for it so it always moves.

A waiting run can be stopped like any other: it ends as Killed without starting.

A waiting run has waitingForLaneSinceUtc set, on the run and in run lists. To see why it’s waiting, read its lane:

const runId = "b7e6d5c4-3a2b-4c1d-8e9f-0a1b2c3d4e5f";
const wait = await mt.runs.lane(runId, { type: "Interaction" });
if (wait.waiting) console.log(wait.reason, `${wait.lanesInUse} of ${wait.laneLimit ?? "unlimited"} in use`, `${wait.ahead} ahead`);

reason is LanesInUse when all your lanes of that kind are busy, or will be once your runs ahead of it start (one of your runs has to free one, or you can add lanes). It’s PlatformBusy when a lane of yours is free for it but the platform has no room yet. ahead counts your runs of the same kind that started before it and are still waiting.

WhatLimit
A file uploaded to a knowledge base10 MB
One write to a file systemabout 100 MB
An API request body30 MB
A tool response passed to the modeltrimmed when very large
Web tools5 queries per search, 10 URLs per fetch, 25 MB per download, 300 web calls per run