Skip to content

.Net: Bug: Unhandled Exception in JsonSerializer.Serialize(ChatHistory) when Trace Logging is Enabled #10708

@kamikyo

Description

@kamikyo

Describe the bug
When the log level is set to Trace, an unhandled exception is triggered in JsonSerializer.Serialize(ChatHistory), causing the program to crash.
The exception occurs in the Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore class, specifically in the GetChatMessageContentsAsync method:

if (this.Logger!.IsEnabled(LogLevel.Trace))
{
   this.Logger.LogTrace("ChatHistory: {ChatHistory}, Settings: {Settings}",
       JsonSerializer.Serialize(chatHistory),
       JsonSerializer.Serialize(executionSettings));
}

Under certain conditions, the chatHistory may contain exception messages, such as:
{Error: Function call processing failed. Correct yourself. Error: Function call arguments were invalid JSON.}.
This causes JsonSerializer.Serialize(chatHistory) to throw the following exception:

System.NotSupportedException: Serialization and deserialization of 'System.Reflection.MethodBase' instances are not supported. Path: $.Items.Exception.InnerException.TargetSite.

To Reproduce
Steps to reproduce the behavior:

  1. Cause Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore.GetFunctionCallContents to throw an exception, for example:

Image

This can be easily achieved by ensuring that toolCall.FunctionArguments contains invalid content when calling:

JsonSerializer.Deserialize<KernelArguments>(toolCall.FunctionArguments);
(This is a common occurrence, which is why I discovered this bug.)

  1. Once an exception is generated, functionCallContent.Exception will have content.
  2. In Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore's GetChatMessageContentsAsync method, the code proceeds as follows:
// Process function calls by invoking the functions and adding the results to the chat history.
// Each function call triggers auto-function-invocation filters, which can terminate the process.
// In such cases, we return the last message in the chat history.
var lastMessage = await this.FunctionCallsProcessor.ProcessFunctionCallsAsync(
    chatMessageContent,
    chatExecutionSettings,
    chatHistory,
    requestIndex,
    (FunctionCallContent content) => IsRequestableTool(chatOptions.Tools, content),
    functionCallingConfig.Options ?? new FunctionChoiceBehaviorOptions(),
    kernel,
    isStreaming: false,
    cancellationToken).ConfigureAwait(false);
if (lastMessage != null)
{
    return [lastMessage];
}

The FunctionCallsProcessor.ProcessFunctionCallsAsync method stores the exception message from chatMessageContent into chatHistory. This leads to the issue when JsonSerializer.Serialize(chatHistory) is executed next.

Expected behavior
The exception should be caught to prevent the program from crashing.
A better approach would be to format the exception message so that it can be serialized properly. This would allow the exception information to be logged without causing the program to crash.

Screenshots
Exception Details:

System.NotSupportedException: Serialization and deserialization of 'System.Reflection.MethodBase' instances are not supported. Path: $.Items.Exception.InnerException.TargetSite.
---> System.NotSupportedException: Serialization and deserialization of 'System.Reflection.MethodBase' instances are not supported.
  at System.Text.Json.Serialization.Converters.UnsupportedTypeConverter`1.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
  at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
  at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
  at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWriteAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Converters.IEnumerableDefaultConverter`2.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1.GetMemberAndWriteJson(Object obj, WriteStack& state, Utf8JsonWriter writer)
  at System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryWrite(Utf8JsonWriter writer, T value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Converters.IEnumerableDefaultConverter`2.OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonCollectionConverter`2.OnTryWrite(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  --- End of inner exception stack trace ---
  at System.Text.Json.ThrowHelper.ThrowNotSupportedException(WriteStack& state, Exception innerException)
  at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
  at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed)
  at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo`1 jsonTypeInfo)
  at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
  at Microsoft.SemanticKernel.Connectors.OpenAI.ClientCore.GetChatMessageContentsAsync(String targetModel, ChatHistory chatHistory, PromptExecutionSettings executionSettings, Kernel kernel, CancellationToken cancellationToken) in G:\others\semantic-kernel\dotnet\src\Connectors\Connectors.OpenAI\Core\ClientCore.ChatCompletion.cs:line 144
  at Microsoft.SemanticKernel.ChatCompletion.ChatCompletionServiceExtensions.GetChatMessageContentAsync(IChatCompletionService chatCompletionService, ChatHistory chatHistory, PromptExecutionSettings executionSettings, Kernel kernel, CancellationToken cancellationToken) in G:\others\semantic-kernel\dotnet\src\SemanticKernel.Abstractions\AI\ChatCompletion\ChatCompletionServiceExtensions.cs:line 83

Platform

  • Language: C# .NET 8
  • Source: main branch of repository

Image

  • AI model: qwen2.5:7b
  • IDE: Visual Studio
  • OS: Windows

Metadata

Metadata

Labels

.NETIssue or Pull requests regarding .NET codebugSomething isn't working

Type

Projects

Status

Sprint: Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions