Errors and Reliability
Exceptions
Every exception that the SDK raises is a SmarterError, so one except clause catches them
all. The SDK follows the platform’s own rule that exceptions subclass one hierarchy
(ADR-012).
SmarterError
├── SmarterConfigurationError the client has no api key or base url
├── SmarterValueError an argument is invalid, before any request is sent
├── ResourceNotFoundError a resource was not found, by the API or by find()
├── SmarterPromptError a streamed prompt failed
└── APIError
├── APIConnectionError the request got no response
│ └── APITimeoutError
├── APIResponseValidationError the response doesn't match the SDK's model of it
└── APIStatusError the API returned a 4xx or 5xx status
├── BadRequestError 400
├── AuthenticationError 401
├── PermissionDeniedError 403
├── NotFoundError 404, also a ResourceNotFoundError
├── ConflictError 409
├── UnprocessableEntityError 422
├── RateLimitError 429
└── InternalServerError 5xx
An APIStatusError carries the response’s status_code, a readable message, the parsed
body, and, when the platform sent a journaled error, its error, whose errorClass (also
error_class) is the name of the platform’s exception, e.g. SAMBrokerErrorNotFound.
from smarter import NotFoundError, SmarterError
try:
client.manifests.describe("LLMClient", "no_such_client")
except NotFoundError as e:
print(e.status_code, e.message, e.error_class)
except SmarterError as e:
print("something else went wrong:", e)
An APIResponseValidationError usually means that the SDK and the platform are of incompatible
versions. Compare client.version().api.version with the SDK’s smarter.__version__.
Retries and timeouts
A request that failed for a transient reason is retried, by default twice, with exponential backoff
and jitter, honoring the response’s Retry-After. Transient means: no response, a timeout, or a
408, 429, 502 or 504 status. A 503 is retried only when it didn’t come from the platform itself,
e.g. from a load balancer, because the platform answers 503 for a resource that isn’t ready, which a
retry won’t change.
client = Smarter(max_retries=0, timeout=120)
Retrying a prompt can bill a prompt twice, if the first attempt reached the LLM. Set
max_retries=0 where that matters more than resilience.
Logging
The SDK logs to the smarter logger hierarchy, and, as a library should, adds no handlers unless
you ask it to. Set SMARTER_LOG=info to log each request’s method, url, status and duration to
stderr, or SMARTER_LOG=debug to log the bodies too. Or configure the logger as any other:
import logging
logging.getLogger("smarter.client").setLevel(logging.DEBUG)
API keys are never logged: they are masked to their last four characters.