stride3d/stride · error · InvalidOperationException

Cannot resize the manifold store, manifolds have not been…

Error message

Cannot resize the manifold store, manifolds have not been flushed yet

What it means

ContactEventsManager buffers contact manifolds per simulation worker. Resizing the worker count would reallocate the store array, which is only safe when every store is empty; otherwise buffered manifold data would be lost. The library refuses the resize until the simulation has flushed its manifolds.

Solutions

  1. Delay the resize until after the simulation step has flushed manifolds (e.g. outside the physics update loop).
  2. Drain/flush contact events before calling ResizeWorkerCount.
  3. Only set worker count during initialization before the simulation starts producing contacts.
  4. If the buffered data is disposable, clear/flush the stores explicitly before resizing.

Example fix

// before
contactEvents.ResizeWorkerCount(4); // mid-frame, manifolds pending -> throws
// after
await EndPhysicsFrameAsync(); // ensure manifolds flushed
contactEvents.ResizeWorkerCount(4);
Defensive patterns

Strategy: validation

Validate before calling

// only resize when no manifolds are pending
if (AreAllManifoldStoresEmpty(contactEvents))
    contactEvents.ResizeWorkerCount(newWorkerCount);

Try / catch

try { contactEvents.ResizeWorkerCount(n); } catch (InvalidOperationException) { QueueResizeAfterFlush(n); }

Prevention

When it happens

Trigger: Calling ContactEventsManager.ResizeWorkerCount(newWorkerCount) while some IPerTypeManifoldStore in _manifoldStoresPerWorker still contains unflushed manifolds (typeStore.IsEmpty() == false), e.g. between a simulation step and manifold flush.

Common situations: Changing MaxWorkerThreads/worker count on the Bepu simulation while contact events are pending mid-simulation or during initialization before the first flush; resizing during gameplay after collisions were detected but events not yet dispatched.

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 stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/6a573aa79408c413. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs:59

    }

    public void Dispose()
    {
        _simulation.Simulation.Timestepper.BeforeCollisionDetection -= TrackActivePairs;
        if (_bodyListenerFlags.Flags.Allocated)
            _bodyListenerFlags.Dispose(_pool);
        if (_staticListenerFlags.Flags.Allocated)
            _staticListenerFlags.Dispose(_pool);
    }

    public void ResizeWorkerCount(int newWorkerCount)
    {
        foreach (var workerStore in _manifoldStoresPerWorker)
        {
            foreach (var typeStore in workerStore)
            {
                if (typeStore.IsEmpty() == false)
                    throw new InvalidOperationException("Cannot resize the manifold store, manifolds have not been flushed yet");
            }
        }

        _manifoldStoresPerWorker = new IPerTypeManifoldStore[newWorkerCount][];
        for (int i = 0; i < _manifoldStoresPerWorker.Length; i++)
            _manifoldStoresPerWorker[i] = [];
    }

    /// <summary>
    /// Begins listening for events related to the given collidable.
    /// </summary>
    public void Register(CollidableComponent collidable)
    {
        var reference = collidable.CollidableReference ?? throw new InvalidOperationException($"This Collidable's {nameof(CollidableReference)} should exist");
        if (reference.Mobility == CollidableMobility.Static)
            _staticListenerFlags.Add(reference.RawHandleValue, _pool);
        else
            _bodyListenerFlags.Add(reference.RawHandleValue, _pool);

View on GitHub (pinned to 96fad776d2)