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
- Delay the resize until after the simulation step has flushed manifolds (e.g. outside the physics update loop).
- Drain/flush contact events before calling ResizeWorkerCount.
- Only set worker count during initialization before the simulation starts producing contacts.
- 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
- Resize worker counts only during initialization before the simulation runs
- Never resize between a simulation step and its manifold flush
- Route worker-count changes through a deferred post-flush hook
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
- PhysicsComponent has not been attached yet.
- Unable to unload the current profile.
- Bundle has not been loaded.
- Not initialized.
- Not running.
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)