{"record":{"id":"94355b0734054398","repo":"JamesNK/Newtonsoft.Json","slug":"the-defaultreferenceresolver-can-only-be-used-inte","errorCode":null,"errorMessage":"The DefaultReferenceResolver can only be used internally.","messagePattern":"The DefaultReferenceResolver can only be used internally\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs","lineNumber":46,"sourceCode":"using System.Globalization;\n\nnamespace Newtonsoft.Json.Serialization\n{\n    internal class DefaultReferenceResolver : IReferenceResolver\n    {\n        private int _referenceCount;\n\n        private BidirectionalDictionary<string, object> GetMappings(object context)\n        {\n            if (!(context is JsonSerializerInternalBase internalSerializer))\n            {\n                if (context is JsonSerializerProxy proxy)\n                {\n                    internalSerializer = proxy.GetInternalSerializer();\n                }\n                else\n                {\n                    throw new JsonException(\"The DefaultReferenceResolver can only be used internally.\");\n                }\n            }\n\n            return internalSerializer.DefaultReferenceMappings;\n        }\n\n        public object ResolveReference(object context, string reference)\n        {\n            GetMappings(context).TryGetByFirst(reference, out object? value);\n            return value!;\n        }\n\n        public string GetReference(object context, object value)\n        {\n            BidirectionalDictionary<string, object> mappings = GetMappings(context);\n\n            if (!mappings.TryGetBySecond(value, out string? reference))\n            {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/JamesNK/Newtonsoft.Json/blob/4f73e74372445108d2c1bda37b36e6f5e43402e0/Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs#L28-L64","documentation":"DefaultReferenceResolver.GetMappings (used for PreserveReferencesHandling) requires the context object passed to its methods to be a JsonSerializerInternalBase or a JsonSerializerProxy. If the context is anything else, it throws a JsonException (line 46). The default reference resolver is internal-only and depends on the internal serializer's bidirectional reference map.","triggerScenarios":"Invoking IReferenceResolver methods (GetReference/ResolveReference/AddReference) on the default resolver with a context object that is not the internal serializer. Reachable via a custom IReferenceResolver that delegates to the default resolver, or by assigning DefaultReferenceResolver (via reflection) and passing a foreign context.","commonSituations":"Building a custom reference resolver that reuses the default with a non-internal context, or wrapping the serializer in a custom proxy that does not expose the internal serializer. Since DefaultReferenceResolver is internal, normal users hit this only through unusual reflection/proxy setups.","solutions":["Do not reuse the internal DefaultReferenceResolver from a custom resolver; implement IReferenceResolver with your own reference store.","If you implement a custom serializer proxy, ensure the context you pass is the actual internal serializer (or a JsonSerializerProxy that resolves to one).","Prefer the public PreserveReferencesHandling option with the default resolver rather than wiring references manually."],"exampleFix":"// before\nvar resolver = (IReferenceResolver)Activator.CreateInstance(typeof(DefaultReferenceResolver), nonPublic: true);\nvar id = resolver.GetReference(myCustomContext, value); // throws\n\n// after\npublic sealed class MyReferenceResolver : IReferenceResolver {\n    private readonly Dictionary<object, string> _ids = new(ReferenceEqualityComparer.Instance);\n    public string GetReference(object context, object value) { /* assign/return id */ }\n    // implement ResolveReference, AddReference, IsReferenced\n}","handlingStrategy":"validation","validationCode":"// Do not reuse the internal default resolver. Validate your custom resolver works with public context.\npublic sealed class MyResolver : IReferenceResolver {\n    private readonly Dictionary<object, string> _byObject = new(ReferenceEqualityComparer.Instance);\n    private readonly Dictionary<string, object> _byRef = new();\n    public string GetReference(object context, object value) {\n        if (!_byObject.TryGetValue(value, out var id)) { id = (_byObject.Count + 1).ToString(); _byObject[value] = id; _byRef[id] = value; }\n        return id;\n    }\n    public object ResolveReference(object context, string reference) => _byRef[reference];\n    public void AddReference(object context, string reference, object value) { _byRef[reference] = value; _byObject[value] = reference; }\n    public bool IsReferenced(object context, object value) => _byObject.ContainsKey(value);\n}","typeGuard":"// n/a: DefaultReferenceResolver is internal; users cannot type-check against it directly","tryCatchPattern":"try { json = JsonConvert.SerializeObject(obj, settings); }\ncatch (JsonException ex) when (ex.Message == \"The DefaultReferenceResolver can only be used internally.\")\n{\n    // replace the internal resolver with a custom IReferenceResolver implementation\n}","preventionTips":["Never reuse the internal DefaultReferenceResolver from a custom resolver; implement your own IReferenceResolver.","Prefer the public PreserveReferencesHandling option over manual reference wiring.","If you write a serializer proxy, ensure it exposes the internal serializer or is a JsonSerializerProxy."],"tags":["reference-resolution","preserve-references","internal-api","misuse"],"analyzedSha":"4f73e74372445108d2c1bda37b36e6f5e43402e0","analyzedAt":"2026-08-07T06:10:08.596Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}