Error Handling
Copy MarkdownSycophant uses Splode for structured error
handling. All errors implement Splode.Error and are organized into three
classes.
Error Classes
Invalid (caller errors)
Errors you can fix before sending the request:
| Error | When |
|---|---|
MissingModel | No model argument provided |
MissingCredentials | No credentials found for the provider |
InvalidParams | Parameters fail Zoi schema validation |
InvalidSchema | Response schema is malformed (Zoi or JSON Schema) |
InvalidResponse | Response fails JSON Schema validation |
InvalidSerialization | Deserialization encounters unknown type |
InvalidEmbeddingInput | Embedding input is malformed |
InvalidRegistration | Module registration error |
Provider (remote API errors)
Errors from the LLM provider's API:
| Error | When |
|---|---|
RateLimited | API rate limit exceeded (HTTP 429) |
ServerError | Provider returned 5xx |
BadRequest | Provider rejected the request (HTTP 400) |
AuthenticationFailed | Invalid credentials (HTTP 401/403) |
ModelNotFound | Model does not exist at the provider |
ContentFiltered | Content was blocked by safety filters |
ResponseInvalid | Provider returned unparseable response |
Unknown
Catch-all for errors that don't fit the above categories.
Pattern Matching
Match on specific error modules for targeted handling:
case Sycophant.generate_text("openai:gpt-4o-mini", messages) do
{:ok, response} ->
response.text
{:error, %Sycophant.Error.Provider.RateLimited{}} ->
Process.sleep(1000)
retry()
{:error, %Sycophant.Error.Provider.ContentFiltered{}} ->
"Content was blocked by safety filters"
{:error, %Sycophant.Error.Invalid.MissingCredentials{}} ->
"Please configure your API key"
{:error, error} ->
Logger.error("LLM request failed: #{Splode.Error.message(error)}")
"Something went wrong"
endMatching by Class
Match on the error class to handle categories:
case Sycophant.generate_text("openai:gpt-4o-mini", messages) do
{:ok, response} ->
{:ok, response}
{:error, %{class: :invalid}} ->
# Caller mistake -- fix the request and retry
{:error, :bad_request}
{:error, %{class: :provider}} ->
# Remote failure -- log and maybe retry
{:error, :provider_error}
{:error, _} ->
{:error, :unknown}
endError Messages
Use Splode.Error.message/1 to get a human-readable description:
{:error, error} = Sycophant.generate_text("bad:model", messages)
Splode.Error.message(error)
#=> "Model not found: bad:model"Telemetry Integration
Failed requests emit [:sycophant, :request, :error] telemetry events with
the error and its class in the metadata. See the Telemetry
guide for details.