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

  1. Ensure the property actually exists in the JObject before renaming (check via obj.Property(name) != null).
  2. Avoid mutating the JObject from multiple threads; JObject is not thread-safe for concurrent writes.
  3. 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

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


AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07). Data as JSON: /api/errors/8ce42aba83f5f9fd. Report an issue: GitHub.