dotnet data_error ai_generated true

System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 64. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.

ID: dotnet/serialization-cycle-detected

Also available as: JSON · Markdown · 中文
90%Fix Rate
85%Confidence
1Evidence
2023-02-14First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
net6.0 active
net7.0 active
net8.0 active
net9.0 active

Root Cause

The JSON serializer encountered a circular reference (e.g., a parent referencing a child that references the parent) during serialization, which it cannot handle by default in System.Text.Json.

generic

中文

JSON 序列化器在序列化过程中遇到了循环引用(例如,父对象引用子对象,子对象又引用父对象),而 System.Text.Json 默认无法处理这种情况。

Official Documentation

https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/preserve-references

Workarounds

  1. 95% success Use ReferenceHandler.Preserve in JsonSerializerOptions. Example: 'var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve }; var json = JsonSerializer.Serialize(obj, options);' This adds $id and $ref metadata to handle cycles.
    Use ReferenceHandler.Preserve in JsonSerializerOptions. Example: 'var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve }; var json = JsonSerializer.Serialize(obj, options);' This adds $id and $ref metadata to handle cycles.
  2. 90% success Apply [JsonIgnore] on the property causing the cycle. For example, if 'Order.Customer' references 'Customer.Orders', add '[JsonIgnore]' on 'Customer.Orders' in the DTO or view model.
    Apply [JsonIgnore] on the property causing the cycle. For example, if 'Order.Customer' references 'Customer.Orders', add '[JsonIgnore]' on 'Customer.Orders' in the DTO or view model.
  3. 85% success Use Data Transfer Objects (DTOs) that flatten the object graph and avoid circular references. For example, create 'OrderDto' with 'CustomerId' instead of a full 'Customer' object.
    Use Data Transfer Objects (DTOs) that flatten the object graph and avoid circular references. For example, create 'OrderDto' with 'CustomerId' instead of a full 'Customer' object.

中文步骤

  1. Use ReferenceHandler.Preserve in JsonSerializerOptions. Example: 'var options = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve }; var json = JsonSerializer.Serialize(obj, options);' This adds $id and $ref metadata to handle cycles.
  2. Apply [JsonIgnore] on the property causing the cycle. For example, if 'Order.Customer' references 'Customer.Orders', add '[JsonIgnore]' on 'Customer.Orders' in the DTO or view model.
  3. Use Data Transfer Objects (DTOs) that flatten the object graph and avoid circular references. For example, create 'OrderDto' with 'CustomerId' instead of a full 'Customer' object.

Dead Ends

Common approaches that don't work:

  1. Setting MaxDepth to a very high value (e.g., 1024) 90% fail

    This only increases the depth limit but does not resolve the cycle; the serializer will still throw an exception when it detects the cycle at any depth.

  2. Using Newtonsoft.Json instead of System.Text.Json without configuring ReferenceLoopHandling 85% fail

    Newtonsoft.Json also throws an error by default on cycles unless ReferenceLoopHandling.Ignore is set, so simply switching libraries does not fix the issue.

  3. Adding [JsonIgnore] on all navigation properties randomly 75% fail

    This may remove necessary data and break API contracts; a targeted approach is needed to identify the specific cycle.