08 - Error Handling¶
This document specifies the exception hierarchy, when each exception is thrown, and the recovery strategies available to users.
Exception Hierarchy¶
java.lang.RuntimeException
+-- AgentEnsembleException (base for all framework exceptions)
+-- ValidationException (invalid configuration)
+-- TaskExecutionException (task-level failure)
+-- ConstraintViolationException (post-execution hierarchical constraint failure)
+-- AgentExecutionException (agent-level failure)
+-- ToolExecutionException (tool infrastructure failure)
+-- MaxIterationsExceededException (agent stuck in tool loop)
+-- PromptTemplateException (template variable error)
+-- RateLimitTimeoutException (rate limit wait timeout exceeded)
All exceptions are unchecked (extend RuntimeException). This is a deliberate design choice: AgentEnsemble is a framework, and forcing users to catch-or-declare everywhere would make the API cumbersome. Users who want to handle errors can catch specific types; others can let exceptions propagate naturally.
Exception Definitions¶
AgentEnsembleException¶
Base exception for all framework errors.
public class AgentEnsembleException extends RuntimeException {
public AgentEnsembleException(String message) { ... }
public AgentEnsembleException(String message, Throwable cause) { ... }
public AgentEnsembleException(Throwable cause) { ... }
}
ValidationException¶
Thrown when ensemble, agent, or task configuration is invalid. This is always a user error (incorrect configuration).
public class ValidationException extends AgentEnsembleException {
public ValidationException(String message) { ... }
}
When thrown: - Agent build with null/blank role, goal, or null LLM - Agent build with invalid maxIterations (<= 0) - Agent build with invalid tool objects - Ensemble.run() with empty tasks or agents list - Ensemble.run() when a task references an agent not in the ensemble - Ensemble.run() with circular context dependencies - Ensemble.run() with context ordering violations (sequential workflow) - Duplicate tool names detected
TaskExecutionException¶
Thrown when a task fails during execution. Carries context about the failure and any completed work.
public class TaskExecutionException extends AgentEnsembleException {
/** Description of the task that failed. */
private final String taskDescription;
/** Role of the agent that was executing the task. */
private final String agentRole;
/**
* Outputs from tasks that completed successfully before this failure.
* Allows partial recovery of work.
*/
private final List<TaskOutput> completedTaskOutputs;
public TaskExecutionException(String message, String taskDescription,
String agentRole, List<TaskOutput> completedTaskOutputs) { ... }
public TaskExecutionException(String message, String taskDescription,
String agentRole, List<TaskOutput> completedTaskOutputs,
Throwable cause) { ... }
// Getters for all fields
}
When thrown:
- Any unrecoverable error during task execution in the WorkflowExecutor
- Wraps AgentExecutionException or MaxIterationsExceededException with additional context
Recovery:
- getCompletedTaskOutputs() returns all outputs from tasks that succeeded before the failure
- Users can inspect these for partial results
- getCause() reveals the underlying error (LLM timeout, agent stuck, etc.)
ConstraintViolationException¶
Thrown after a hierarchical workflow completes when one or more roles listed in HierarchicalConstraints.requiredWorkers were never called by the Manager during the workflow execution.
public class ConstraintViolationException extends AgentEnsembleException {
/**
* Human-readable descriptions of each constraint that was violated.
* Each entry describes a single unfulfilled requirement (e.g.,
* "Required worker 'QA Engineer' was never delegated a task").
*/
private final List<String> violations;
/**
* Outputs from workers that did complete successfully before the
* constraint check. Allows inspection of partial results.
*/
private final List<TaskOutput> completedTaskOutputs;
public ConstraintViolationException(List<String> violations) { ... }
public ConstraintViolationException(List<String> violations,
List<TaskOutput> completedTaskOutputs) { ... }
public ConstraintViolationException(List<String> violations,
Throwable cause) { ... }
// Getters for all fields
@Override
public String getMessage() { ... }
}
When thrown:
- After the hierarchical workflow manager completes, when HierarchicalConstraints.requiredWorkers contains roles that were never called during the workflow execution
getMessage() format:
- Single violation: "Hierarchical constraint violated: <violation description>"
- Multiple violations: "Hierarchical constraints violated (N): <v1>; <v2>; ..."
NOT thrown for pre-delegation constraint failures:
Pre-delegation constraints (allowedWorkers, maxCallsPerWorker, globalMaxDelegations, requiredStages) are enforced before a delegation is approved and return a DelegationPolicyResult.reject() result back to the Manager LLM — they do not produce exceptions.
Recovery:
- getViolations() lists all unfulfilled requirements, identifying which required roles were skipped
- getCompletedTaskOutputs() provides partial results from workers that did execute
AgentExecutionException¶
Thrown when the agent execution itself fails (LLM errors, infrastructure failures).
public class AgentExecutionException extends AgentEnsembleException {
/** Role of the agent that failed. */
private final String agentRole;
/** Description of the task the agent was working on. */
private final String taskDescription;
public AgentExecutionException(String message, String agentRole,
String taskDescription, Throwable cause) { ... }
// Getters
}
When thrown: - LLM throws an exception (timeout, authentication failure, rate limiting, network error) - LLM returns a response that LangChain4j cannot parse - Any unexpected error during the agent's LLM interaction loop
NOT thrown for: - Tool execution errors (these are caught and fed back to the LLM) - Max iterations exceeded (has its own exception type) - Empty LLM responses (these are logged as warnings, not errors)
ToolExecutionException¶
Represents a tool infrastructure failure. This exception is primarily used for internal tracking and logging; it is NOT typically thrown to halt execution.
public class ToolExecutionException extends AgentEnsembleException {
/** Name of the tool that failed. */
private final String toolName;
/** Input that was passed to the tool. */
private final String toolInput;
public ToolExecutionException(String message, String toolName,
String toolInput, Throwable cause) { ... }
// Getters
}
Behavior: - When a tool throws during execution, the error is caught and converted to an error message string - The error message is fed back to the LLM as the tool's result - The LLM can then decide to retry, use a different tool, or produce a final answer - This allows graceful degradation rather than hard failure on tool errors
MaxIterationsExceededException¶
Thrown when an agent exceeds its maximum tool call iterations without producing a final answer.
public class MaxIterationsExceededException extends AgentEnsembleException {
/** Role of the stuck agent. */
private final String agentRole;
/** Description of the task the agent was working on. */
private final String taskDescription;
/** The configured maximum. */
private final int maxIterations;
/** How many tool calls were actually made. */
private final int toolCallsMade;
public MaxIterationsExceededException(String agentRole,
String taskDescription, int maxIterations, int toolCallsMade) { ... }
// Getters
}
When thrown:
- Agent has made > maxIterations tool calls AND 3 "stop" messages have been sent to the LLM AND the LLM still hasn't produced a final text response
Recovery:
- User can increase maxIterations on the agent
- User can simplify the task description
- User can provide fewer/simpler tools
PromptTemplateException¶
Thrown when template variable resolution fails.
public class PromptTemplateException extends AgentEnsembleException {
/** Variable names that were in the template but not in the inputs map. */
private final List<String> missingVariables;
/** The original template string (for debugging). */
private final String template;
public PromptTemplateException(String message,
List<String> missingVariables, String template) { ... }
// Getters
}
When thrown:
- TemplateResolver.resolve() finds {variable} placeholders with no matching key in the inputs map
- Always reports ALL missing variables, not just the first one
Recovery:
- User provides the missing variables in ensemble.run(Map.of("var1", "value1", ...))
- Or user removes the {variable} placeholders from the task description/expectedOutput
RateLimitTimeoutException¶
Thrown by RateLimitedChatModel when a thread cannot acquire a rate-limit token within
the configured wait timeout.
public class RateLimitTimeoutException extends AgentEnsembleException {
/** The rate limit that was being enforced. */
private final RateLimit rateLimit;
/** The wait timeout that was exceeded. */
private final Duration waitTimeout;
public RateLimitTimeoutException(RateLimit rateLimit, Duration waitTimeout) { ... }
// Getters
}
When thrown:
- A calling thread waited longer than waitTimeout for a rate-limit token to become available
- Typically propagates through AgentExecutor and is wrapped in TaskExecutionException
Recovery:
- Increase waitTimeout on RateLimitedChatModel.of(model, rateLimit, timeout)
- Reduce concurrency (fewer parallel tasks sharing the same bucket)
- Increase the RateLimit to allow more requests per period
Error Recovery Strategy Summary¶
| Exception | Where Thrown | Recovery |
|---|---|---|
ValidationException |
build() or run() |
Fix configuration. No partial results. |
TaskExecutionException |
WorkflowExecutor |
Inspect completedTaskOutputs for partial work. Fix cause. |
ConstraintViolationException |
HierarchicalWorkflowExecutor |
Inspect violations to see which required roles were skipped. Inspect completedTaskOutputs for partial results. |
AgentExecutionException |
AgentExecutor |
Wrapped in TaskExecutionException. Check LLM connectivity/credentials. |
ToolExecutionException |
Tool execution | NOT propagated (error fed to LLM). Fix tool implementation if persistent. |
MaxIterationsExceededException |
AgentExecutor |
Increase maxIterations, simplify task, or reduce tools. |
PromptTemplateException |
Template resolution | Provide missing variables or fix template syntax. |
RateLimitTimeoutException |
RateLimitedChatModel |
Increase waitTimeout, reduce concurrency, or increase RateLimit. |
Exception Flow Diagram¶
ensemble.run(inputs)
|
+-- ValidationException (config invalid)
+-- PromptTemplateException (template vars missing)
|
+-- WorkflowExecutor.execute()
|
+-- TaskExecutionException (wraps below)
| |
| +-- AgentExecutionException (LLM failed)
| +-- MaxIterationsExceededException (agent stuck)
| +-- RateLimitTimeoutException (rate bucket exhausted, wait timed out)
| |
| (Tool errors are NOT exceptions -- fed back to LLM)
|
+-- ConstraintViolationException (hierarchical: required workers never called)
(pre-delegation policy violations are NOT exceptions -- DelegationPolicyResult.reject())