microsoft/autogen · error · ArgumentNullException
choice.FinishReason
Error message
choice.FinishReason
What it means
MistralChatMessageConnector.PostProcessMessage switches on choice.FinishReason to decide between TextMessage (stop/length) and ToolCallMessage (tool_calls). A null FinishReason cannot be dispatched, so ArgumentNullException is thrown with paramName "choice.FinishReason".
Source
Thrown at dotnet/src/AutoGen.Mistral/Middleware/MistralChatMessageConnector.cs:152
};
}
});
}
private IMessage PostProcessMessage(ChatCompletionResponse response, IAgent from)
{
if (response.Choices is null)
{
throw new ArgumentNullException("response.Choices");
}
if (response.Choices?.Count != 1)
{
throw new NotSupportedException("response.Choices.Count != 1");
}
var choice = response.Choices[0];
var finishReason = choice.FinishReason ?? throw new ArgumentNullException("choice.FinishReason");
if (finishReason == Choice.FinishReasonEnum.Stop || finishReason == Choice.FinishReasonEnum.Length)
{
return new TextMessage(Role.Assistant, choice.Message?.Content ?? throw new ArgumentNullException("choice.Message.Content"), from: from.Name);
}
else if (finishReason == Choice.FinishReasonEnum.ToolCalls)
{
var functionContents = choice.Message?.ToolCalls ?? throw new ArgumentNullException("choice.Message.ToolCalls");
var toolCalls = functionContents.Select(f => new ToolCall(f.Function.Name, f.Function.Arguments) { ToolCallId = f.Id }).ToList();
return new ToolCallMessage(toolCalls, from: from.Name);
}
else
{
throw new NotSupportedException($"FinishReason {finishReason} is not supported");
}
}
private IMessage? ProcessChatCompletionResponse(IMessage<ChatCompletionResponse> message, IAgent agent)View on GitHub (pinned to 027ecf0a37)
Solutions
- Make sure streaming responses go through the streaming connector path (ProcessChatCompletionResponse), not the non-streaming PostProcessMessage.
- Log the raw choice JSON to confirm finish_reason is genuinely missing, then update AutoGen.Mistral if the API contract changed.
- Catch ArgumentNullException around the completion call and retry once — some null-finish-reason responses are transient.
Defensive patterns
Strategy: validation
Validate before calling
var fr = response.Choices?[0].FinishReason;
if (fr is null)
{
// response shape not dispatchable: log raw choice JSON, do not map
} Try / catch
try { var reply = await mistralAgent.SendAsync(msg); } catch (ArgumentNullException ex) when (ex.ParamName == "choice.FinishReason") { /* retry once; report schema drift if persistent */ } Prevention
- Route streaming chunks only through streaming paths
- Keep AutoGen.Mistral aligned with the live API schema
- Retry transient null-finish-reason responses once
When it happens
Trigger: A Mistral chat completion choice whose finish_reason JSON field is absent/null — e.g. truncated error responses, streaming chunk shapes accidentally fed to the non-streaming path, or API schema changes.
Common situations: Feeding a streaming chunk payload into the non-streaming PostProcessMessage path; Mistral API version drift making finish_reason optional on some responses; intermediate/keep-alive responses with empty deltas.
Related errors
- response.Choices
- response.Choices.Count != 1
- FinishReason {finishReason} is not supported
- Missing MISTRAL_API_KEY environment variable
- Missing MISTRAL_API_KEY environment variable.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/d1c6f8dd9df130fb.
Report an issue: GitHub.