Exceptions
Most TnsAI exceptions extend TnsAIException, an unchecked exception that says whether a retry can help and how long to wait. An action call that fails throws ActionExecutionException, whose category names the cause.
TnsAIException
| Method | Returns |
|---|---|
isRetryable() | true for transient failures such as network errors, rate limits and server errors |
getErrorCode() | TNSAI- plus the class name without Exception, upper-cased: TNSAI-NETWORK, TNSAI-RATELIMIT |
getSuggestedRetryDelayMs() | 1000 when retryable and 0 otherwise, unless a subclass sets its own |
getMaxRetryAttempts() | 3 when retryable and 0 otherwise, unless a subclass sets its own |
The error code is stable, so it works as a metric or log tag.
ActionExecutionException
An action call that fails throws ActionExecutionException. It carries getActionName(), getActionType(), getCategory() and getDetailedMessage(), a one-line summary for logs.
| Category | Retryable | Cause |
|---|---|---|
NETWORK | Yes | Connection timeout, DNS failure |
PARAMETER | No | Missing parameter, wrong type |
CLIENT_ERROR | No | HTTP 4xx response |
SERVER_ERROR | Yes | HTTP 5xx response |
VALIDATION | No | A failed contract, guardrail or validation check |
LLM | Yes | Model error, quota exceeded |
MCP | Yes | MCP tool error |
INVOCATION | No | Reflection failure, method not found |
UNKNOWN | No | Anything else |
Two cases land in VALIDATION:
- A failed
@Contractclause. The cause is aContractViolationExceptionwithgetContractKind(),getViolatedExpression()andgetBindings(). See Contracts. - An
LLMaction on an agent with noLLMClient. The call fails instead of returningnull, so@Fallbackcan run. See LLM actions.
ApprovalRequiredException and security exceptions are not wrapped. They reach the caller as they are.
LLMException
A failed model call throws LLMException. getErrorType() names the cause, and getModel() the model.
ErrorType | Retryable | Cause |
|---|---|---|
MODEL_NOT_FOUND | No | Model not found or unavailable |
AUTHENTICATION_FAILED | No | Invalid API key |
CONTENT_FILTERED | No | Content policy violation |
INVALID_REQUEST | No | Invalid request |
MODEL_OVERLOADED | Yes | Model overloaded; suggested delay 5000 ms |
CONTEXT_TOO_LONG | No | Context length exceeded |
SERVER_ERROR | Yes | Provider server error; suggested delay 2000 ms |
MALFORMED_TOOL_CALL | No | The model sent bad JSON or missed a field in a tool call |
CAPABILITY_MISMATCH | No | The model lacks a required capability |
UNKNOWN | Yes | Anything else |
LLMCapabilityException extends LLMException for a feature the model or provider does not support, such as streaming, vision or structured output. ToolCallNotSupportedException extends it for tool calls.
Other exceptions
| Exception | Retryable | Fields |
|---|---|---|
RateLimitException | Yes, up to 5 times. The delay is the provider's Retry-After, or 60000 ms. | getRetryAfterMs(), getService(), getRemainingQuota() |
NetworkException | Yes | host and port |
TimeoutException | Yes | timeout and operation |
ValidationException | No | |
KnowledgeNotReadyException | No. It extends ValidationException. | The host class, the source and the Problem: MISSING, EMPTY or UNREADABLE |
ApprovalRequiredException | No | action name and reason |
TaskCompleteException | No | Not implemented: no framework loop catches it, and @CompletionSignal is not read. |
Handle a failure
Choose a recovery from the category of an action failure. For a chat turn, catch the most specific type first.
package com.example.tnsai.docs;
import com.tnsai.agents.Agent;
import com.tnsai.exceptions.ActionExecutionException;
import com.tnsai.exceptions.LLMException;
import com.tnsai.exceptions.RateLimitException;
import com.tnsai.exceptions.TnsAIException;
import java.util.Map;
public final class ExceptionsExample {
private ExceptionsExample() {}
// An action call: choose a recovery from the category.
static Object forecast(Agent agent) {
try {
return agent.executeAction("forecast", Map.of("city", "Paris"));
} catch (ActionExecutionException e) {
System.err.println(e.getDetailedMessage());
return switch (e.getCategory()) {
case NETWORK, SERVER_ERROR -> "retry in " + e.getSuggestedRetryDelayMs() + " ms";
case PARAMETER, VALIDATION -> "fix the arguments for " + e.getActionName();
default -> throw e;
};
}
}
// A chat turn: catch the most specific type first.
static String ask(Agent agent, String question) {
try {
return agent.chat(question);
} catch (RateLimitException e) {
return "rate limited, retry in " + e.getSuggestedRetryDelayMs() + " ms";
} catch (LLMException e) {
if (e.getErrorType() == LLMException.ErrorType.CONTEXT_TOO_LONG) {
return "shorten the question";
}
throw e;
} catch (TnsAIException e) {
System.err.println(e.getErrorCode() + " retryable=" + e.isRetryable());
throw e;
}
}
}To retry inside the framework instead, see Resilience.
Related
- Actions: the steps where an action call can fail.
- Contracts: the clauses behind
VALIDATION. - Resilience: retries, timeouts and fallbacks.
- Knowledge: sources that raise
KnowledgeNotReadyException.