JamesNK/Newtonsoft.Json · error · JsonException
The DefaultReferenceResolver can only be used internally.
Error message
The DefaultReferenceResolver can only be used internally.
What it means
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.
Source
Thrown at Src/Newtonsoft.Json/Serialization/DefaultReferenceResolver.cs:46
using System.Globalization;
namespace Newtonsoft.Json.Serialization
{
internal class DefaultReferenceResolver : IReferenceResolver
{
private int _referenceCount;
private BidirectionalDictionary<string, object> GetMappings(object context)
{
if (!(context is JsonSerializerInternalBase internalSerializer))
{
if (context is JsonSerializerProxy proxy)
{
internalSerializer = proxy.GetInternalSerializer();
}
else
{
throw new JsonException("The DefaultReferenceResolver can only be used internally.");
}
}
return internalSerializer.DefaultReferenceMappings;
}
public object ResolveReference(object context, string reference)
{
GetMappings(context).TryGetByFirst(reference, out object? value);
return value!;
}
public string GetReference(object context, object value)
{
BidirectionalDictionary<string, object> mappings = GetMappings(context);
if (!mappings.TryGetBySecond(value, out string? reference))
{View on GitHub (pinned to 4f73e74372)
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.
Example fix
// before
var resolver = (IReferenceResolver)Activator.CreateInstance(typeof(DefaultReferenceResolver), nonPublic: true);
var id = resolver.GetReference(myCustomContext, value); // throws
// after
public sealed class MyReferenceResolver : IReferenceResolver {
private readonly Dictionary<object, string> _ids = new(ReferenceEqualityComparer.Instance);
public string GetReference(object context, object value) { /* assign/return id */ }
// implement ResolveReference, AddReference, IsReferenced
} Defensive patterns
Strategy: validation
Validate before calling
// Do not reuse the internal default resolver. Validate your custom resolver works with public context.
public sealed class MyResolver : IReferenceResolver {
private readonly Dictionary<object, string> _byObject = new(ReferenceEqualityComparer.Instance);
private readonly Dictionary<string, object> _byRef = new();
public string GetReference(object context, object value) {
if (!_byObject.TryGetValue(value, out var id)) { id = (_byObject.Count + 1).ToString(); _byObject[value] = id; _byRef[id] = value; }
return id;
}
public object ResolveReference(object context, string reference) => _byRef[reference];
public void AddReference(object context, string reference, object value) { _byRef[reference] = value; _byObject[value] = reference; }
public bool IsReferenced(object context, object value) => _byObject.ContainsKey(value);
} Type guard
// n/a: DefaultReferenceResolver is internal; users cannot type-check against it directly
Try / catch
try { json = JsonConvert.SerializeObject(obj, settings); }
catch (JsonException ex) when (ex.Message == "The DefaultReferenceResolver can only be used internally.")
{
// replace the internal resolver with a custom IReferenceResolver implementation
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/94355b0734054398.
Report an issue: GitHub.