Docs


Errors and exceptions

The SDK exception hierarchy and how to handle the most common failures.

Last updated June 3, 2026

Every SDK failure raises a subclass of vilvik.VilvikError. You can catch the base class to handle any SDK error in one place, or catch a specific subclass to branch on the kind of failure. The mapping to HTTP status codes mirrors Errors.

The hierarchy

VilvikError
โ”œโ”€โ”€ TimeoutError
โ””โ”€โ”€ APIError
    โ”œโ”€โ”€ AuthenticationError    (401, 403)
    โ”œโ”€โ”€ NotFoundError          (404)
    โ”œโ”€โ”€ ValidationError        (400, 422)
    โ””โ”€โ”€ RateLimitError         (429)

What each error means

Exception When it is raised
VilvikError Base class. Catch this to handle any SDK error in a single block.
TimeoutError A polling helper such as Results.wait_for exceeded its deadline before the run finished.
APIError The API returned a non-2xx response that did not match a more specific subclass (typically 5xx server errors).
AuthenticationError API key missing, revoked, expired, or under-scoped for the requested action.
NotFoundError The resource does not exist or is not visible to this key.
ValidationError The request body failed server-side validation.
RateLimitError Too many requests for the key's rate limit window.

Common attributes on APIError

Attribute Type What it holds
status_code int HTTP status returned by the server.
code str Stable machine-readable code (for example "validation_failed").
message str Human-readable summary.
request_id str The X-Request-Id echoed back by the API. Quote this in support requests.
payload dict The full decoded JSON body, preserved for debugging.

RateLimitError also exposes retry_after: the number of seconds the server advises you to wait before retrying. It is None when the server did not advise one.

Catching errors

Branch on the specific failure when you can:

import vilvik

try:
    submission = client.submissions.create(fitness_func=src, num_genes=5)
except vilvik.ValidationError as exc:
    print("Bad parameters:", exc.message, exc.payload)
except vilvik.AuthenticationError:
    print("Your API key was rejected.")
except vilvik.RateLimitError as exc:
    wait = exc.retry_after or 30
    print(f"Rate-limited; retrying in {wait}s.")
except vilvik.APIError as exc:
    print(f"API error {exc.status_code}: {exc.message} (request {exc.request_id})")

Or catch the base class when you want to log everything uniformly:

try:
    submission = client.submissions.create(...)
except vilvik.VilvikError as exc:
    logger.exception("vilvik call failed: %s", exc)
    raise

Retries

The transport retries idempotent requests (GET, HEAD) on transient failures up to max_retries times. Write requests (POST, DELETE) are never retried automatically because they could create duplicates. If you want a write to be safely retryable, pass an idempotency_key (the SDK adds one for you by default on create and reexecute).

Thanks for the feedback!