microsoft/semantic-kernel · error · KernelException
Agent Failure - Run terminated: {run.Status} [{run.Id}]: {ru
Error message
Agent Failure - Run terminated: {run.Status} [{run.Id}]: {run.LastError?.Message ?? "Unknown"} What it means
In the non-streaming InvokeAsync loop, after each poll the run's status is checked; if it is terminal but not Completed (e.g., Failed, Cancelled, Expired, Incomplete), a KernelException is thrown carrying the run id, status, and last error message.
Source
Thrown at dotnet/src/Agents/OpenAI/Internal/AssistantThreadActions.cs:164
FunctionCallsProcessor functionProcessor = new(logger);
// This matches current behavior. Will be configurable upon integrating with `FunctionChoice` (#6795/#5200)
FunctionChoiceBehaviorOptions functionOptions = new() { AllowConcurrentInvocation = true, AllowParallelCalls = true };
// Evaluate status and process steps and messages, as encountered.
HashSet<string> processedStepIds = [];
Dictionary<string, FunctionResultContent> functionSteps = [];
do
{
// Check for cancellation
cancellationToken.ThrowIfCancellationRequested();
// Poll run and steps until actionable
await PollRunStatusAsync().ConfigureAwait(false);
// Is in terminal state?
if (run.Status.IsTerminal && run.Status != RunStatus.Completed)
{
throw new KernelException($"Agent Failure - Run terminated: {run.Status} [{run.Id}]: {run.LastError?.Message ?? "Unknown"}");
}
List<RunStep> steps = [];
await foreach (var step in client.GetRunStepsAsync(run.ThreadId, run.Id, cancellationToken: cancellationToken).ConfigureAwait(false))
{
steps.Add(step);
}
// Is tool action required?
if (run.Status == RunStatus.RequiresAction)
{
logger.LogOpenAIAssistantProcessingRunSteps(nameof(InvokeAsync), run.Id, threadId);
// Execute functions in parallel and post results at once.
FunctionCallContent[] functionCalls = steps.SelectMany(step => ParseFunctionStep(agent, step)).ToArray();
if (functionCalls.Length > 0)
{
// Emit function-call contentView on GitHub (pinned to c028a0c7dc)
Solutions
- Inspect run.LastError.Message in the exception to find the root cause.
- Make invoked function tools robust (catch internal errors, return a string result) so they don't fail the run.
- Retry with exponential backoff for transient failures (rate limits, 5xx).
- Increase run/timeout settings or reduce tool output size if the run expired or hit length limits.
Example fix
// before
await foreach (var r in agent.InvokeAsync(thread)) { /* no error handling */ }
// after
try {
await foreach (var r in agent.InvokeAsync(thread)) { /* ... */ }
}
catch (KernelException ex) when (ex.Message.Contains("Run terminated")) {
logger.LogError(ex, "Assistant run failed; retrying");
await Task.Delay(backoff);
} Defensive patterns
Strategy: retry
Try / catch
int attempts = 0;
retry:
try { await foreach (var r in agent.InvokeAsync(thread)) { /* ... */ } }
catch (KernelException ex) when (ex.Message.Contains("Run terminated") && attempts++ < 3) {
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempts)));
goto retry;
} Prevention
- Make function tools return error strings instead of throwing.
- Cap tool output size to avoid length-limit failures.
- Log run.LastError.Message for every failure to find recurring causes.
- Set reasonable run timeouts/iteration limits.
When it happens
Trigger: An OpenAI assistant run ends in a non-success terminal state: a function tool threw, the run exceeded max iterations/tokens, it hit a content-policy block, rate limit, or expired before completing.
Common situations: A kernel function tool raises an exception the assistant surface treats as a run failure; long-running tools causing expiration; quota/rate-limit responses; malformed tool outputs.
Related errors
- Agent Failure - Run not created for thread: ${threadId}
- The thread could not be created due to an error response fro
- The thread could not be deleted due to an error response fro
- The message could not be added to the thread due to an error
- The message could not be added to the thread due to an error
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/c5b9291eaf8e8ffa.
Report an issue: GitHub.