microsoft/autogen · error · NotSupportedException

FinishReason {finishReason} is not supported

Error message

FinishReason {finishReason} is not supported

What it means

NotSupportedException indicating the Mistral response's finish_reason is none of stop, length, or tool_calls. The connector only maps these three terminal reasons; anything else (e.g. 'model_length', 'function_call' from legacy APIs, or a new Mistral finish reason) is rejected.

Source

Thrown at dotnet/src/AutoGen.Mistral/Middleware/MistralChatMessageConnector.cs:166

            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")
        {
            throw new NotSupportedException($"VarObject {response.VarObject} is not supported");
        }
        if (response.Choices is null)
        {
            throw new ArgumentNullException("response.Choices");
        }

        if (response.Choices?.Count != 1)
        {
            throw new NotSupportedException("response.Choices.Count != 1");

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Capture the raw finish_reason string from the API response to identify the exact value.
  2. If it is a legitimate new reason, extend the if/else chain in the connector to handle it (or map unknown reasons to a text message with diagnostics).
  3. Switch from legacy function_call parameters to the current tool-calling API if using an OpenAI-compatible shim.
  4. Upgrade AutoGen.Mistral; newer releases may support additional finish reasons.

Example fix

// before
else
{
    throw new NotSupportedException($"FinishReason {finishReason} is not supported");
}

// after
else
{
    // degrade gracefully: surface whatever content exists instead of crashing
    return new TextMessage(Role.Assistant, choice.Message?.Content ?? string.Empty, from: from.Name);
}
Defensive patterns

Strategy: fallback

Validate before calling

var supported = new[] { Choice.FinishReasonEnum.Stop, Choice.FinishReasonEnum.Length, Choice.FinishReasonEnum.ToolCalls };
if (!supported.Contains(choice.FinishReason!.Value))
{
    // map unknown finish reasons to a safe text message before the connector throws
    return new TextMessage(Role.Assistant, choice.Message?.Content ?? "[unsupported finish reason]", from: agent.Name);
}

Type guard

static bool IsSupportedFinishReason(Choice.FinishReasonEnum? r) => r is Choice.FinishReasonEnum.Stop or Choice.FinishReasonEnum.Length or Choice.FinishReasonEnum.ToolCalls;

Try / catch

catch (NotSupportedException ex) when (ex.Message.Contains("FinishReason"))
{
    logger.LogWarning("Unhandled Mistral finish reason: {Message}", ex.Message);
    // degrade to retry or end the turn instead of crashing the orchestration
}

Prevention

When it happens

Trigger: Non-streaming Mistral completion whose finish_reason is a value outside {stop, length, tool_calls}. Examples: legacy 'function_call' responses from function-calling APIs, new finish reasons Mistral introduces (e.g. content-filter related), or enum parsing that yields an unexpected value.

Common situations: Mistral introducing a new finish_reason after the SDK was vendored; using a Mistral-compatible endpoint (OpenAI-style proxies) that emit 'function_call'; explicitly requesting legacy function calling instead of tool calling.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/58f1fee5e79fdfc6. Report an issue: GitHub.