Where did you hear about us?
1 of 6
Errors & limits

When something goes wrong.

Errors come back as a JSON envelope with a stable type, a human message, and a request_id you can send us when reporting an issue.

Actual response - invalid key (HTTP 401)
{"type": "error", "error": {
   "type": "authentication_error",
   "message": "Invalid or revoked API key.",
   "request_id": "063f8b83-eee2-4383-a5cf-11e4bcd29d7c"
 }}
HTTPMeaningWhat to do
400Malformed body (missing or wrong-type field), or a store id outside the allowed format on createThe message names the exact field - fix and retry.
401Invalid or revoked API keyCheck the key; issue a new one in the console.
402Out of balance, no card on file, or a tier capTop up or add a card in the console. The response carries balance_cents and floor_cents, so you can tell which one stopped you.
403The selected model does not support an option you sent (image, max_images, verify, form)Pick a model that supports it; GET /api/v1/models lists them. The call is refused so you are not charged for something that would not run.
404No such memory, store, or imageCheck the id. get_image also answers 404 when the memory exists but carries no image. A store id that differs from an existing store only by punctuation also answers 404.
409A name clash, or a write already in flightA store id that differs from an existing store only in ., _ or - cannot be created, so pick another id. Creating the same id again is not a conflict: it answers 200 with "exists". Workspace names are unique within an account. A second write to one store within 100 ms is refused and nothing is stored: the SDKs retry it after the wait the service asks for, and over HTTP you retry it yourself.
413Request body over 10MBBase64 runs about 33% larger than the file it encodes, so resize the image before encoding it.
429Rate limitedThe SDK already retries these for you, with backoff and jitter, honouring Retry-After. Getting one means the retries ran out - lower your concurrency rather than wrapping a loop of your own around it.
501This model's engine does not implement that endpointImages and revision history need a newer engine. GET /api/v1/models lists which models serve what.
5xxServer-side problemRetry with backoff, but not blindly. The SDKs retry 502, 503, 504 and 408 on calls that only read, such as search, recall and listing stores, on the DELETE calls, and on the memory writes, which carry an idempotency key so a repeat is answered with the first result instead of storing twice. Other writes sent as POST are not retried on these statuses because the server may already have done the work. When you resend a write yourself, give it an idempotency key so a repeat cannot double-write. A 503 with restoring: true means an idle store is being brought back; retry shortly. Include request_id if you contact us.

Every error is a WosError, and each status also has a class of its own - BadRequestError, AuthenticationError, PaymentRequiredError, PermissionDeniedError, NotFoundError, ConflictError, RateLimitError, GoneError, ServerError, APIConnectionError. Catch the one you mean to handle instead of comparing numbers. In Python and TypeScript an error also carries the service's error type and the rest of its error object as details. A 413 or 422 is a BadRequestError. A retired model answers 410, raised as GoneError (in Rust, is_gone() is true): name a live model instead, from list_models(). Until it retires, a model scheduled to retire names the day in a Sunset header on its answers, and the SDKs warn once with that date.

# SDK error handling (Python)
from wontopos import Client, WosError, RateLimitError, PaymentRequiredError, GoneError

try:
    mem.search("...", user_id="alice")
except PaymentRequiredError: ...      # 402 - top up
except RateLimitError: ...            # 429 - the SDK already retried; slow down
except GoneError: ...                 # 410 - the model retired; pick one from list_models()
except WosError as e: ...            # e.status, e.message, e.request_id
except (ValueError, TypeError): ...    # never left the client

Some mistakes never reach us. A blank store id, a malformed API key or idempotency key, a malformed image argument, and a metadata key that names a store or an idempotency key (userId, store_id, idempotencyKey, in any case or spelling) are refused before the request goes out. Those raise ValueError or TypeError, not WosError, so an except WosError on its own will not catch them. A store id in the wrong format, such as an email address, only logs a warning here; the service refuses it on create with a 400.

Key safety. Your key is shown once at creation and stored only as a hash on our side. Keep it in an environment variable; if it leaks, revoke it in the console - revocation is immediate.

Rate limits are per account, shared across all your keys, and scale with your tier - see Usage tiers. Your account's usage is shown in the console.