Network/API calls return {:ok, value} or {:error, %TypeSafeSDK.Error{}}.
case TypeSafeSDK.list_models(client) do
{:ok, response} ->
Enum.map(response.models, & &1.name)
{:error, %TypeSafeSDK.Error{type: type, status: status, message: message}} ->
IO.inspect(%{type: type, status: status, message: message}, label: "API failure")
enderror.type uses these primary values:
:bad_request(400):authentication(401):permission_denied(403):not_found(404):unprocessable_entity(422):rate_limit(429):internal_server(5xx):api_errorfor other unsuccessful statuses:connection,:timeout,:response_validation,:configuration
The error also preserves status, body, headers, TypeSafe request ID, retry-after
milliseconds, the raw Pristine.Response, and an endpoint string when Pristine
transport metadata provides it. Successful SystemOneResponse and
ListModelsResponse values likewise retain request_id and raw_http_response;
use their request_id!/1 / raw_http_response!/1 accessors when metadata is
required rather than optional.
TypeSafeSDK.RetryPolicy defaults to the supplied Python SDK's public values:
two retries, 0.5-second exponential initial backoff, 5-second cap, 0.25 jitter,
retrying 408/429/5xx plus connection/timeouts, honoring Retry-After, and a
30-second retry budget. The budget includes the first attempt and stops before
a retry delay would reach the limit, preserving the last error. Set timeout: nil
in the retry policy to remove that budget. Zero initial backoff or a zero cap
disables backoff; Retry-After remains effective unless explicitly disabled.
Pristine 0.3.0 status-range prerequisite
The Python SDK retries every HTTP status from 500 through 599. TypeSafeSDK
represents that rule with Pristine 0.3.0's provider-level
status_retry_ranges contract rather than enumerating one hundred integer
overrides or changing Pristine's global defaults. Exact caller-selected HTTP
statuses continue to use exact provider overrides, while the default full 5xx
set compacts to one 500..599 rule.
Per-call RetryPolicy values rebuild the provider profile used for that call,
so replacing http_statuses really changes classification rather than only
changing the backoff loop. respect_retry_after: false also clears Pristine's
classified retry delay for that call.
0.2.0 local errors and policy queries
Strict constructors/preparation/evaluation use :invalid_request, with
error.path component lists, field_path and structured details.
Relational response failures retain :response_validation plus the original HTTP
status/body/headers/request ID. Batch failures add details.batch_index;
worker crashes use :task_exit, and worker timeouts use :timeout with
details.scope == :batch. Missing required runtime guarantees use
:runtime_capability. evaluate! / system_one! raise the normalized error.
TypeSafeSDK.Error.retryable?(error)
TypeSafeSDK.Error.retryable?(error, client.retry)
TypeSafeSDK.Error.retry_after(error) # milliseconds or nilRetryability describes the error category under a policy, not remaining attempt budget or an instruction to automatically resubmit exhausted work. Validation and local batch-lifecycle errors are not classified as transport-retryable.
At-least-once execution and ambiguous failures
Retries can execute an evaluation more than once. A connection failure after submission does not prove that the server failed to process or bill the request. The SDK preserves the existing retry defaults; disable retry explicitly when the risk of replay outweighs resilience. A batch task timeout or local cancellation also cannot undo a remote operation. Never treat retryability as an exactly-once execution guarantee, and do not infer total billed tokens from the final successful response alone. Error bodies/details are available to the caller but must not be dumped into production telemetry without an explicit privacy review.