microsoft/autogen · error · ArgumentNullException
choice.Message.Content
Error message
choice.Message.Content
What it means
Thrown by MistralChatMessageConnector when a Mistral chat completion finishes with reason 'stop' or 'length' but the returned choice.Message.Content is null. The connector assumes a text finish always carries content, so a null Content is treated as a programming/contract violation rather than a normal result. It is an ArgumentNullException thrown via the null-coalescing throw expression at MistralChatMessageConnector.cs:156.
Source
Thrown at dotnet/src/AutoGen.Mistral/Middleware/MistralChatMessageConnector.cs:156
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)
{
var response = message.Content;
if (response.VarObject != "chat.completion.chunk")
{View on GitHub (pinned to 027ecf0a37)
Solutions
- Inspect the raw HTTP response body for the failing request to see the actual Content JSON shape (log it before deserialization).
- If Content can legitimately be empty, map null to string.Empty instead of throwing: choice.Message?.Content ?? string.Empty.
- If the API payload changed, update the ChatCompletionResponse model (e.g. change Content from string to a nullable/JsonElement property) to match the current Mistral API.
- Upgrade AutoGen.Mistral to the latest version in case the connector was already patched for this shape.
Example fix
// before
return new TextMessage(Role.Assistant, choice.Message?.Content ?? throw new ArgumentNullException("choice.Message.Content"), from: from.Name);
// after
return new TextMessage(Role.Assistant, choice.Message?.Content ?? string.Empty, from: from.Name); Defensive patterns
Strategy: validation
Validate before calling
var choice = response.Choices[0];
if (choice.FinishReason is Choice.FinishReasonEnum.Stop or Choice.FinishReasonEnum.Length
&& string.IsNullOrEmpty(choice.Message?.Content))
{
// model finished with no text; decide policy before the connector throws
choice.Message.Content = string.Empty;
} Type guard
static bool HasTextContent(Choice choice) =>
choice?.Message?.Content is string s && s.Length > 0; Try / catch
catch (ArgumentNullException ex) when (ex.Message.Contains("choice.Message.Content"))
{
// treat as empty completion and retry or continue conversation
logger.LogWarning("Mistral returned empty content for stop/length finish");
} Prevention
- Log raw completion JSON in development to detect schema drift early
- Pin the Mistral API/model version used in production
- Add integration tests covering empty-content completions
When it happens
Trigger: Calling a Mistral agent (non-streaming path) where the model's finish_reason is 'stop' or 'length' while choice.Message.Content deserializes to null. This happens when the model returns only tool_calls with empty content, when the JSON payload shape changes (new Mistral API version), or when Content is an unexpected JSON type (e.g. an array payload) that System.Text.Json maps to null.
Common situations: Mistral API returning content as a structured payload instead of a plain string; a model finishing with 'length' after emitting no text; version drift between the vendored Mistral SDK models and the live Mistral API; a response produced entirely of tool calls but mislabeled finish_reason.
Related errors
- choice.Message.ToolCalls
- Value was null.
- Failed to deserialize response
- 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/2a376ace81260e41.
Report an issue: GitHub.