JamesNK/Newtonsoft.Json · error · InvalidOperationException

Cannot change {0} during a collection change event.

Error message

Cannot change {0} during a collection change event.

What it means

CheckReentrancy throws InvalidOperationException when you try to mutate a JContainer (Add/Insert/Remove/SetItem/Clear) from within a CollectionChanged or ListChanged handler raised by that same container. The internal _busy flag guards against reentrant edits that would corrupt the token linked-list (Previous/Next/Parent).

Source

Thrown at Src/Newtonsoft.Json/Linq/JContainer.cs:134

            if (copyAnnotations)
            {
                CopyAnnotations(this, other);
            }

            int i = 0;
            foreach (JToken child in other)
            {
                TryAddInternal(i, child, false, copyAnnotations);
                i++;
            }
        }

        internal void CheckReentrancy()
        {
#if (HAVE_COMPONENT_MODEL || HAVE_INOTIFY_COLLECTION_CHANGED)
            if (_busy)
            {
                throw new InvalidOperationException("Cannot change {0} during a collection change event.".FormatWith(CultureInfo.InvariantCulture, GetType()));
            }
#endif
        }

        internal virtual IList<JToken> CreateChildrenCollection()
        {
            return new List<JToken>();
        }

#if HAVE_COMPONENT_MODEL
        /// <summary>
        /// Raises the <see cref="AddingNew"/> event.
        /// </summary>
        /// <param name="e">The <see cref="AddingNewEventArgs"/> instance containing the event data.</param>
        protected virtual void OnAddingNew(AddingNewEventArgs e)
        {
            _addingNew?.Invoke(this, e);
        }

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Do not mutate the raising collection inside its own handler; defer the change to after the event completes.
  2. Queue the desired mutation and apply it from outside the handler (e.g. via a dispatcher or a separate pass).
  3. Operate on a different JContainer instance, or detach the handler before mutating.

Example fix

// before
container.CollectionChanged += (s, e) => container.Add(extra);
// after
container.CollectionChanged += (s, e) => pendingAdds.Add(extra);
// apply pendingAdds to container after the handler returns
Defensive patterns

Strategy: validation

Validate before calling

// never mutate the raising container in its own handler.
container.CollectionChanged += (s, e) => {
    // queue work instead of mutating 'container' here
    _deferred.Enqueue(() => container.Add(extra));
};

Try / catch

try { container.Add(item); }
catch (InvalidOperationException ex) when (ex.Message.Contains("during a collection change event")) {
    // defer the mutation outside the event handler
}

Prevention

When it happens

Trigger: Subscribing to CollectionChanged (or ListChanged) and calling Add/Remove/Replace/Insert/Clear on the sender inside the handler.

Common situations: WPF/WinForms data-binding sync code that mutates the bound collection in a change callback; reactive code that re-enters the collection.

Related errors


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