Limits & Timeouts (v2, Beta)
The numbers a client author needs to build against: request size, timeouts, pagination, batch and ingest bounds, and backpressure. These are enforced server-side — design your chunking, retry, and pagination around them rather than discovering them at runtime. Values are the defaults for a standard Aito server; a managed tier may set stricter quotas (see Quotas).
When a limit produces an error, it uses the structured error envelope — { "kind": "error", "data": { "code", "message" } } — except the two transport-level limits noted below (request size and the request timeout), which are enforced by the HTTP layer before the query handler runs.
Request size
- Max request body: 10 MB for a normal
POST(a query, or a non-streamed data write). A larger body is rejected with HTTP 413 (Payload Too Large). This is a hard, AWS-API-Gateway-derived constant — it is not configurable per deployment. - Response bodies are also capped at 10 MB. A query whose result would exceed that is truncated at the transport layer, so keep result sets bounded (see pagination) rather than fetching everything in one call.
- Streamed ingest (
POST .../data/{table}/batchand.../import) is not bound by the 10 MB whole-body cap — it is parsed incrementally — but each individual JSON object must be ≤ 16 MB.
To stay under the 10 MB ceiling: split large uploads into batches (see Batch & ingest) and bound reads with limit.
Timeouts
- A single HTTP request has a 15-minute deadline (idle, request, and linger timeouts are all 15 minutes). A query still executing at 15 minutes has its connection closed by the server.
- There is no separate per-query execution cap — a query's server-side budget is the 15-minute request deadline together with the admission gate. Most queries return in milliseconds; the 15-minute ceiling exists for heavy analytics and ingest.
_evaluate and maxTime
_evaluate behaves differently depending on the engine of the from table:
- On a legacy
type: "table"(rep1) table,_evaluatehonorsmaxTime(seconds): default 300 s, hard maximum 3600 s. On reachingmaxTimeit truncates gracefully — returning the metrics computed so far plus awarningsnote — it does not error. - On a
type: "collection"(rep2) table — the v2 default —_evaluatecurrently runs the full test set with nomaxTimebudget. It is bounded only by the 15-minute HTTP request timeout: if the test set is large enough to exceed 15 minutes on one request, the connection closes with no result.
Two ways to keep a rep2 evaluation inside the window:
- Narrow
testSource(a smaller held-out fold) so the run finishes well under 15 minutes. - Run it as a job (below) — the way to evaluate a large test set without the 15-minute ceiling.
Long-running operations: jobs
Any v2 operation can be submitted as an asynchronous job instead of being held open on one request. This is the escape hatch for work that can exceed the 15-minute request timeout — a large _evaluate, a bulk import/batch, an optimize.
POST /api/v2/jobs/_evaluate → 201 { "id": "…", "path": "Evaluate", "startedAt": … }
GET /api/v2/jobs → list running + recently-finished jobs
GET /api/v2/jobs/{id} → status; once done, adds "status": "ok" | "failed"
GET /api/v2/jobs/{id}/result → the result (byte-identical to the sync response);
202 while still running
DELETE /api/v2/jobs/{id} → cooperative cancel
- The
jobs/prefix works in front of every v2 op — query ops (jobs/_query,jobs/_predict,jobs/_evaluate, …) and write ops (jobs/data/{table}/batch,jobs/data/{table}/optimize,jobs/data/_delete, …). - A job's
/resultis byte-identical to what the synchronous endpoint would return, including the error envelope on failure — a failed job reports"status": "failed"with the reason, so it never fails silently. - Poll
GET /api/v2/jobs/{id}until astatusfield appears, then fetch/result. Jobs are retained for a while after finishing, then expire from the result cache (a later fetch is a404). - Jobs are shared across API versions — a job submitted at
/api/v2/jobsis also visible and cancellable at/api/v1/jobs/{id}. - Cancellation is cooperative:
_evaluatechecks for cancellation per test row, so aDELETEstops it promptly; some other ops finish their current unit of work before stopping.
Result size & pagination
- Default page size is 10 for every read (
_search,_query,_predict,_recommend,_relate,$knn,$patterns). Setlimitto change it. - There is no maximum-
limitclamp — a largelimitis honored, bounded only by the 10 MB response cap.offsetdefaults to0. - Paginate with
offset+limit. The response carriesoffset,limit, and a realtotal. totaldoes not mean the same thing on every endpoint. On row endpoints it is the count of matching rows; on_predict/_recommendit is the number of distinct candidate values; on_matchit is the matched-row count alongside a smallerhitsarray. Don't build a "showing 10 of N rows" pagination loop ontotalfrom a predict/recommend/match response.- SQL note: a
SELECTwith noLIMITis unbounded (it fetches every matching row, subject to the 10 MB cap). Always addLIMITin_sql.
Batch & ingest
_batch (an array of queries) is fail-fast. The sub-queries run in order within one transaction; if any one errors, the whole request returns that single error envelope — there is no partial result array and no per-element error object. If query 3 of 10 fails, you get one error, not seven results and an error. Retry the whole batch once the cause is fixed.
Data writes stream and chunk automatically:
| Bound | Value |
|---|---|
| Chunk size (rows committed per flush) | 50,000 (raise with ?batchSize=, clamped to 250,000) |
| Flush window | 10 s |
| Max size of one JSON object | 16 MB |
| Total rows per import | unbounded (subject to quotas) |
Idempotency — retrying a timed-out write. A write has no implicit deduplication: replaying an insert that timed out duplicates rows, unless the table declares a primaryKey and you pass ?on_conflict=update or ?on_conflict=ignore (the default is error). Define a key and an on_conflict policy before you build retry logic — see Identity, keys & deduplication. Because a large ingest can approach the 15-minute request timeout, chunking it into smaller batches also makes each batch independently retryable.
Rate limiting & backpressure
-
There is no per-request rate limit by default. A token-bucket rate limiter exists but is opt-in per database/tenant (managed tiers may enable it, returning
429withX-RateLimit-*headers). -
Always-on backpressure is admission control. When the server's in-flight query weight exceeds its budget, or a request's projected wait exceeds ~20 s, it returns
429with aRetry-Afterheader. This is a back-off-and-retry signal, not a permanent failure. Heavier operations consume more of the budget:Operation Admission weight _search,_predict,$similarity1 _recommend,_match2 _relate5 _evaluate10 So a burst of
_evaluate/_relatecalls hits the gate far sooner than the same number of_searchcalls. -
On the public demo host, a shared key can be throttled — treat a
429as "retry with exponential backoff," and honorRetry-After.
Any client that issues concurrent requests should implement 429 + Retry-After handling. It is the one status you should expect under load even when every request is well-formed.
Field & schema limits
- Links resolve multi-hop dotted paths on rep2 collections —
processor.departmentandprocessor.company.nameboth work, andwhere,select, andorderByall traverse the full chain. (A separate, capped and off-by-default feature — using deep linked attributes as prediction evidence — is a different mechanism, not path resolution.) - Vector dimensions are fixed at schema-declaration time — every vector written to a column must match the declared dimension, or the write is rejected (
data.bad_request, 400).
Quotas
Row and disk quotas are off by default on a self-hosted server (a table and the database as a whole are unbounded). A managed tier may enforce them — e.g. a free tier of 10,000 rows per table / 100 MB disk — in which case a write past the quota fails loud with a 4xx rather than silently dropping rows. Check your plan's quotas before a bulk import.
Related
- Common Errors (v2) — the error envelope and the full code catalogue every limit above reports through.
- Evaluation (v2) —
maxTime,testSource, and the truncation note. - Schema Design (v2) —
primaryKey,on_conflict, and vector dimensions. - Environments & Auth (v2) — API keys and the
429throttling model on shared hosts.