JsonException: A possible object cycle was detected
By FoxLearn 3/13/2025 2:56:52 AM 11
This can happen when two objects refer to each other, creating an endless loop.
System.Text.Json.JsonException: A possible object cycle was detected, which is not supported. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth.
This error can be prevented by handling circular references appropriately.
For example:
public class Product { public string Name { get; set; } public decimal Price { get; set; } public Order Order { get; set; } } public class Order { public string OrderNumber { get; set; } public List<Product> Products { get; set; } }
In this example, an Order
contains a list of Product
objects, and each Product
contains a reference back to the Order
.
Solution for .NET 6+ (Using ReferenceHandler.IgnoreCycles
)
Starting from .NET 6+, you can avoid this issue by using ReferenceHandler.IgnoreCycles
in JsonSerializerOptions
. This will ensure that circular references are ignored during serialization:
using System.Text.Json; var order = new Order { OrderNumber = "ORD123", Products = new List<Product> { new Product { Name = "Laptop", Price = 999.99 }, new Product { Name = "Mouse", Price = 29.99 } } }; foreach (var product in order.Products) { product.Order = order; // Circular reference } var json = JsonSerializer.Serialize(order, new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true }); Console.WriteLine(json);
With this approach, circular references are ignored, and the serialization will complete successfully without throwing an exception.
Solution for .NET 5 (Using ReferenceHandler.Preserve
)
In .NET 5, you can use the ReferenceHandler.Preserve
option. This method will include metadata in the serialized JSON to preserve object references:
var json = JsonSerializer.Serialize(order, new JsonSerializerOptions() { ReferenceHandler = ReferenceHandler.Preserve, WriteIndented = true }); Console.WriteLine(json);
This will produce JSON like:
{ "$id": "1", "OrderNumber": "ORD123", "Products": [ { "$id": "2", "Name": "Laptop", "Price": 999.99, "Order": { "$ref": "1" } }, { "$id": "3", "Name": "Mouse", "Price": 29.99, "Order": { "$ref": "1" } } ] }
Solution for Versions Prior to .NET 5 and 6
If you are working with older versions of .NET that don’t support ReferenceHandler
, there are still several options to handle circular references.
Option 1: Use Newtonsoft.Json
with ReferenceLoopHandling.Ignore
You can use Newtonsoft.Json
(Json.NET) to handle circular references with the ReferenceLoopHandling.Ignore
option. First, you need to install the Newtonsoft.Json
package:
Install-Package Newtonsoft.Json
Then, you can serialize the Order
object as follows:
using Newtonsoft.Json; var json = JsonConvert.SerializeObject(order, Formatting.Indented, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); Console.WriteLine(json);
This will generate JSON without circular references.
Option 2: Remove the Circular Reference Property
If a property like Order
in the Product
class is not crucial, you can simply remove it from serialization by marking it with [JsonIgnore]
:
public class Product { public string Name { get; set; } public decimal Price { get; set; } [JsonIgnore] public Order Order { get; set; } // This will be ignored during serialization }
Now when you serialize the Order
object, the circular reference won’t cause an issue.
Option 3: Create a Custom JsonConverter
For more control over the serialization process, you can create a custom JsonConverter
to manually handle the serialization of circular references. For example, here’s how you could serialize the Product
class without causing a circular reference:
public class ProductJsonConverter : JsonConverter<Product> { public override Product Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Custom deserialization logic here if needed return null; } public override void Write(Utf8JsonWriter writer, Product value, JsonSerializerOptions options) { writer.WriteStartObject(); writer.WriteString(nameof(value.Name), value.Name); writer.WriteNumber(nameof(value.Price), value.Price); // Do not serialize the Order reference writer.WriteEndObject(); } }
Then, you can use this custom converter during serialization:
var options = new JsonSerializerOptions() { Converters = { new ProductJsonConverter() }, WriteIndented = true }; var json = JsonSerializer.Serialize(order, options); Console.WriteLine(json);
These are a few ways you can deal with circular references during serialization in .NET, tailored to different versions and libraries.
- How to batch read with Threading.ChannelReader in C#
- How to ignore JSON deserialization errors in C#
- JSON value could not be converted to System.String in C#
- Calling ‘BuildServiceProvider’ from application code results in an additional copy of singleton services being created
- How to use Newtonsoft in ASP.NET Core
- How to use Polly In C#
- Global exception event handlers in C#
- How to Add or overwrite a value in ConcurrentDictionary in C#