dotnet/wpf · error · InvalidOperationException

SR.GenerationInProgress

Error message

SR.GenerationInProgress

What it means

IItemContainerGenerator.StartAt begins a generation pass by creating a Generator; only one generation may be active at a time. Calling StartAt while an existing generator is still active (_generator != null, i.e. its IDisposable not disposed) throws InvalidOperationException(SR.GenerationInProgress).

Solutions

  1. Dispose the IDisposable from each StartAt before calling StartAt again (use a using block)
  2. Ensure exceptions inside generation loops don't leak undisposed generators
  3. Avoid calling generator APIs from multiple threads; generation is single-pass, UI-thread work

Example fix

// before
var g1 = gen.StartAt(pos, dir, true);
var g2 = gen.StartAt(pos, dir, true); // throws
// after
using (gen.StartAt(pos, dir, true))
{
    while (gen.GenerateNext() is DependencyObject c) { gen.Remove(c); }
}
Defensive patterns

Strategy: validation

Validate before calling

// track your own active generation token
if (_activeGeneration == null) _activeGeneration = iicg.StartAt(pos, dir, allow);

Try / catch

try { using (iicg.StartAt(pos, dir, allow)) { /* generate */ } } catch (InvalidOperationException ex) { /* a generation pass is still active */ }

Prevention

When it happens

Trigger: Calling StartAt (or GenerateNext within it) without disposing the IDisposable returned by a previous StartAt; nested generation loops over the same generator.

Common situations: Custom virtualizing panels iterating items with a using-scope bug (early return or exception skipping Dispose); generating containers on two threads against the same generator.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/a10d655aba8c906a. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ItemContainerGenerator.cs:207

        /// Error, as appropriate.
        /// </remarks>
        IDisposable IItemContainerGenerator.StartAt(GeneratorPosition position, GeneratorDirection direction)
        {
            return ((IItemContainerGenerator)this).StartAt(position, direction, false);
        }

        /// <summary> Begin generating at the given position and direction </summary>
        /// <remarks>
        /// This method must be called before calling GenerateNext.  It returns an
        /// IDisposable object that tracks the lifetime of the generation loop.
        /// This method sets the generator's status to GeneratingContent;  when
        /// the IDisposable is disposed, the status changes to ContentReady or
        /// Error, as appropriate.
        /// </remarks>
        IDisposable IItemContainerGenerator.StartAt(GeneratorPosition position, GeneratorDirection direction, bool allowStartAtRealizedItem)
        {
            if (_generator != null)
                throw new InvalidOperationException(SR.GenerationInProgress);

            _generator = new Generator(this, position, direction, allowStartAtRealizedItem);
            return _generator;
        }

        public IDisposable GenerateBatches()
        {
            if (_isGeneratingBatches)
                throw new InvalidOperationException(SR.GenerationInProgress);

            return new BatchGenerator(this);
        }

        DependencyObject IItemContainerGenerator.GenerateNext()
        {
            bool isNewlyRealized;
            if (_generator == null)
                throw new InvalidOperationException(SR.GenerationNotInProgress);

View on GitHub (pinned to 81131a70a4)