question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

I got "Self referencing loop detected with type" without loops...

See original GitHub issue

Source/destination types

using System;
using Newtonsoft.Json;

public class ISomeJsonConverter : JsonConverter<ISome>
 {
    public override void WriteJson(JsonWriter writer, ISome value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }

    public override ISome ReadJson(JsonReader reader, Type objectType, ISome existingValue, bool hasExistingValue,
        JsonSerializer serializer)
    {
        return null;
    }
}
    
[JsonConverter(typeof(ISomeJsonConverter))]
public interface ISome { }

public class Impl : ISome { }

public class Other
{
    public ISome SomeImpl = new Impl();
}

public static void Main()
{
    //Here 'loop detected' exception will be thrown...
    var sdf = JsonConvert.SerializeObject(new Other());
}

Expected behavior

It should just works, without loop exceptions.

Actual behavior

Well, i thought, this kind of construction should work fine, acording to docs (https://www.newtonsoft.com/json/help/html/JsonConverterAttributeClass.htm).

But it throws.

If i add [JsonConverter(typeof(ISomeJsonConverter))], to the field Other.SomeImpl, it will work as expected.

Steps to reproduce

Just run this code, in your IDE

P.S.

I got plenty of classes where interface based serialization used. And it will be nice if i could use JsonConverter attribute on Interface it self, cause it makes classes more clear, due to less attributes.

Hope you could fix it, or at least explain why this is “ok” behaviour.

Kind Regards.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:6

github_iconTop GitHub Comments

3reactions
gwartnescommented, Apr 15, 2022

I feel like I should leave a comment here, because after googling for answers to the same exact issue, I came across this page.

I think what is missing from the OP’s original bug report is the intent of the action they were trying to perform. In my case, my intent was to create a custom JsonConverter that performs a custom Deserialization on a particular type, and executes default Serialization on the same type. My first attempt had me trying OP’s exact same method, because it feels like the right method in order to get whatever the default serialization behavior is: serializer.Serialize(writer, value);, with the same result - the self-referencing loop error. After wasting a couple of hours on the problem, I finally found the solution.

public class ISomeJsonConverter : JsonConverter<ISome>
{
    public override void WriteJson(JsonWriter writer, ISome value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanWrite => false;

    public override ISome ReadJson(JsonReader reader, Type objectType, ISome existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        return null;
    }
}

Somehow, setting CanWrite to return false will actually pass serialization back to the default converter. To me, this is not intuitive at all - I figured that when trying to serialize it would throw the NotImplementedException (spoiler: it doesn’t). And there is nothing anywhere that tells me that this would pass serialization control back to some other converter. It was basically just trial and error that got me here.

3reactions
jakerdycommented, Jan 13, 2021

Well, thanks for this explanation. I got your point of view, that this is not a bug , but a feature. But as a user of json.net library, and with out of clear knowlage of it’s internal behaviours, i (and even my colleagues) couldn’t tell that this particular case isn’t a bug, or not some kind of unintended behaviour.

Again, from user perspective, “reference loop detected”, is a wrong kinda error for this situation at the top level of serialization logic. May be for some internal error handling error it is ok, as one of the factors for resolving more descriptive user facing error, which should tell about bad/wrong library api usage. But for end user it isn’t good enough. Because it missleading. I’ve spent lot of time debugging, and trying figure out where in my project i got loop references (but i was sure that there is no any, and even couldn’t be). But after many googling attempts, trying many different thing i found that, particular scenario (from example), which makes this “loop”. May be i should ask about it on SO, and got answer quicker, but common, this is looks like a bug. This is why i opened this issue. This behaviour should at least be documented, or mentioned somewhere. Like, “if you got ref loop, this might be, because of real loop refs, and also because we couldn’t track some mad attribute usages”, or “you shouldn’t not mark ifaces with JsonConverter atrribute, because it may lead to wierd/strange behaviour at serialization time”, but there is no any of that done anywhere in the docs/examples.

The best way of course will be throwing other type of exception, which is more clear for end user of json.net library, but i don’t know if it possible at all. Anyway, i understood, that my usage of this attribute isn’t compatible with current logic of lib, but it isn’t obvious, and this, i think should be fixed. At least by me writing about this case in issues on github.

About example, and about “bug in my project”. My project little bit more complex than this boiled down example. And, obviously i shouldn’t copy paste 50kloc+ here, to demonstrate where some strange thing happened. This example just shows, how you could get, weird loop ref error. About no point of doing things like that. There actually is point of doing something like that. In my particular case, i got node graph, which stores nodes in a list of INode derived objects, and list of links between them. INode contains common properties, and special property called NodeKind, which used to identify node when deserializing graph from json. I won’t use explicit type handling, because this graph may be used outside of .net runtimes, and in case of refactoring namespaces, i won’t deal with problems when loading some dated graphs with old ns/type names. And i am pretty happy how default serializer doing it’s job when serializing this graphs. This is why JsonConverter from example written exactly like that. It should serialize node in a default way, and deserialize them with custom logic, based on node_kind property which was omited in example cause it doesn’t deal with that error.

I’ve use kinda work around in my project, specifying item converter through JsonProperty attribute for lists. It worked, but i must use it everywhere, to get INode deserialized correctly. Which isn’t as nice as i if could just mark my ifaces/abstract classes with JsonConverter attrib. And forgot about the fact that i should always specify converter type here and there.

Hope that description was clear enough, and problem became more obvious. But in my opinion, this error should be handled somehow else then just throwing loop ref detected.

Json.net is a great project, i really love it, and i hope it could become even better and more user friendly, if this kind of errors will be handled/documented.

Read more comments on GitHub >

github_iconTop Results From Across the Web

JSON.Net Self referencing loop detected
The fix is to ignore loop references and not to serialize them. This behaviour is specified in JsonSerializerSettings . Single JsonConvert with ...
Read more >
Fixing JSON Self Referencing Loop Exceptions
JsonSerializationException: Self referencing loop detected with type. They mean essentially the same thing, that you have two models that reference each ...
Read more >
Self referencing loop error - How to fix
IQueryable result into a JSON string: JsonSerializationException: Self referencing loop detected with type '<ENTITY_TYPE>'.
Read more >
Self referencing loop detected - Microsoft Q&A
JsonSerializationException: Self referencing loop detected for property 'suiviBE' with type 'FollowUpDash.Shared.Models.SuiviBE'. Path '[0].
Read more >
JsonSerializationException: Self referencing loop detected
Here is the detailed error : JsonSerializationException: Self referencing loop detected for property 'normalized' with type 'UnityEngine.Vector3 ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found