JamesNK/Newtonsoft.Json · error · ArgumentException
The specified item does not exist in this KeyedCollection.
Error message
The specified item does not exist in this KeyedCollection.
What it means
JPropertyKeyedCollection (the lookup store behind JObject) throws ArgumentException 'The specified item does not exist in this KeyedCollection.' from ChangeItemKey (JPropertyKeyedCollection.cs:55) when a key change is requested for a token that is not present in the backing dictionary. It protects dictionary/list synchronization during property renames.
Source
Thrown at Src/Newtonsoft.Json/Linq/JPropertyKeyedCollection.cs:55
private static readonly IEqualityComparer<string> Comparer = StringComparer.Ordinal;
private Dictionary<string, JToken>? _dictionary;
public JPropertyKeyedCollection() : base(new List<JToken>())
{
}
private void AddKey(string key, JToken item)
{
EnsureDictionary();
_dictionary![key] = item;
}
protected void ChangeItemKey(JToken item, string newKey)
{
if (!ContainsItem(item))
{
throw new ArgumentException("The specified item does not exist in this KeyedCollection.");
}
string keyForItem = GetKeyForItem(item);
if (!Comparer.Equals(keyForItem, newKey))
{
if (newKey != null)
{
AddKey(newKey, item);
}
if (keyForItem != null)
{
RemoveKey(keyForItem);
}
}
}
protected override void ClearItems()View on GitHub (pinned to 4f73e74372)
Solutions
- Ensure the property actually exists in the JObject before renaming (check via obj.Property(name) != null).
- Avoid mutating the JObject from multiple threads; JObject is not thread-safe for concurrent writes.
- Do not reach into the internal keyed collection via reflection — use the public JObject API.
Example fix
// before: rename with no guarantee the property exists
((JProperty)obj.First).Set(value); // can desync internals under manual key changes
// after: rename via the public, validated path
var prop = obj.Property("oldName");
if (prop != null)
{
var value = prop.Value;
obj.Remove("oldName");
obj.Add("newName", value);
} Defensive patterns
Strategy: validation
Validate before calling
// Verify the property exists before any rename, and use the public API.
var prop = obj.Property("oldName");
if (prop != null)
{
var value = prop.Value;
obj.Remove("oldName");
obj.Add("newName", value);
} Type guard
static bool PropertyExists(JObject o, string name) => o?.Property(name) != null;
Prevention
- Do not reach into JObject's internal keyed collection via reflection.
- Do not mutate a JObject concurrently from multiple threads.
- Rename via remove+add through the public surface, after an existence check.
When it happens
Trigger: Renaming a JObject property (e.g. JObject's internal rename path) when the target JProperty was never inserted, was already removed, or the collection's dictionary was not yet initialized (too few items to build the dictionary).
Common situations: Renaming properties on an empty or freshly-manipulated JObject before its internal dictionary exists; concurrent/desynced mutation where a property is removed mid-rename; direct reflection into the internal collection.
Related errors
- Cannot add or remove items from {0}.
- {0} cannot have multiple values.
- key
- Can not add {0} to {1}.
- Can not add property {0} to {1}. Property with the same name
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/8ce42aba83f5f9fd.
Report an issue: GitHub.