Limits, quotas & concurrency¶
Authoritative platform values — plan around them rather than discovering them at runtime. All per-tenant unless noted.
All are per-tenant unless noted. Numbers are the platform's authoritative values.
Rate limits (token buckets; 429 + Retry-After, and the SDK auto-retries):
- reads ~500/s sustained (burst 1000) · writes ~100/s (burst 200) ·
upload-init ~100/s (burst 200)
- shared-GPU inference (semantic search, foundation/ZERO): 30 burst, ~0.5/s
sustained — deliberately tight; batch work belongs in jobs, not loops.
Concurrency caps (409, typed codes):
- 3 active jobs (JOB_PER_TENANT_CAP) — embed/train/export/bulk compete
tenant-wide; serialize.
- 3 live model deployments · auto-label run scope ≤ 20,000 explicit asset ids ·
1 active API key per user (revoke before re-creating; multi-actor work
needs one key per seeded user).
Resource quotas (RESOURCE_LIMIT_EXCEEDED, 409, checked at create):
- assets: 1M per tenant AND per dataset · datasets 100 · projects 200
- per project: versions 100, classes 1,000, members 50
- per asset: annotations 5,000, comments 200
- models 100 · users 50 per workspace — pending invitations count toward it
Size caps (413/422):
- image ≤ 50 MB and ≤ 80 megapixels; > 100 MB objects need multipart (the SDK's
upload_paths handles this)
- sync batch endpoints: ≤ 1000 items AND ≤ 5 MB body · annotation batch-delete
≤ 500 ids · staged NDJSON import: ≤ 500k rows / 256 MB
- guidelines: 1 MB markdown / 10 MB per image · page limit ≤ 100 (a few wide
list endpoints allow 200)
Gotchas (cost hours if unknown)¶
- Every dict-shaped parameter has a TypedDict in
superb_ai/types/requests.py(AssetFilterParam,MappedAnnotationCreateParam,ProjectScopeParam, …) — read that file for the exact keys instead of guessing (e.g. the filename filter key isq, notfilename). Plain dict literals still work; the TypedDicts are the reference (and a type-checker will validate your keys against them). - Debugging:
export SUPERB_AI_LOG=debug— every request logs asMETHOD path [request-id] -> status in Nmsplus retry warnings, and the bracketed id equals therequest_idin error envelopes AND in the platform's server logs (the SDK sends it asx-request-id). Quote it when reporting. - GPU endpoints are SCHEDULED: GPU-backed endpoints (semantic-search embedder, SAM) run on a schedule and are torn down outside their window — a 503
EMBEDDER_UNAVAILABLE/ SAM-unavailable may mean scheduled-off, not cold-start. Check the current window with your operator; don't retry-loop. Ask the operator to bring them up; don't retry-loop. - Job cap 3 is per-tenant — your parallel jobs compete with everyone on the tenant.
- Sync caps: batch endpoints cap at 1000 items (413 → use the bulk twin); annotation batch-delete caps at 500 ids.
- Uploads confirm asynchronously — S3 PUT success ≠ asset row exists; always poll.
- Presigned URLs: never send your Authorization header to them (different host —
the SDK's
download_to/upload_pathshandle this; don't fetch them with the client). /jobshidescleanup_s3_objectsunless you filter for it explicitly.- Idempotency: job kickoffs auto-generate an
Idempotency-Key; pass your own to make retries replay (same body) — a REUSED key with a DIFFERENT body is a 409. - Deletes are hard — no undo. Version/asset/annotation deletes are permanent (annotation revision snapshots from past submits remain readable).