{"record":{"id":"6a573aa79408c413","repo":"stride3d/stride","slug":"cannot-resize-the-manifold-store-manifolds-have-not-been","errorCode":null,"errorMessage":"Cannot resize the manifold store, manifolds have not been flushed yet","messagePattern":"Cannot resize the manifold store, manifolds have not been flushed yet","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs","lineNumber":59,"sourceCode":"    }\n\n    public void Dispose()\n    {\n        _simulation.Simulation.Timestepper.BeforeCollisionDetection -= TrackActivePairs;\n        if (_bodyListenerFlags.Flags.Allocated)\n            _bodyListenerFlags.Dispose(_pool);\n        if (_staticListenerFlags.Flags.Allocated)\n            _staticListenerFlags.Dispose(_pool);\n    }\n\n    public void ResizeWorkerCount(int newWorkerCount)\n    {\n        foreach (var workerStore in _manifoldStoresPerWorker)\n        {\n            foreach (var typeStore in workerStore)\n            {\n                if (typeStore.IsEmpty() == false)\n                    throw new InvalidOperationException(\"Cannot resize the manifold store, manifolds have not been flushed yet\");\n            }\n        }\n\n        _manifoldStoresPerWorker = new IPerTypeManifoldStore[newWorkerCount][];\n        for (int i = 0; i < _manifoldStoresPerWorker.Length; i++)\n            _manifoldStoresPerWorker[i] = [];\n    }\n\n    /// <summary>\n    /// Begins listening for events related to the given collidable.\n    /// </summary>\n    public void Register(CollidableComponent collidable)\n    {\n        var reference = collidable.CollidableReference ?? throw new InvalidOperationException($\"This Collidable's {nameof(CollidableReference)} should exist\");\n        if (reference.Mobility == CollidableMobility.Static)\n            _staticListenerFlags.Add(reference.RawHandleValue, _pool);\n        else\n            _bodyListenerFlags.Add(reference.RawHandleValue, _pool);","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.BepuPhysics/Stride.BepuPhysics/Definitions/Contacts/ContactEventsManager.cs#L41-L77","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncontactEvents.ResizeWorkerCount(4); // mid-frame, manifolds pending -> throws\n// after\nawait EndPhysicsFrameAsync(); // ensure manifolds flushed\ncontactEvents.ResizeWorkerCount(4);","handlingStrategy":"validation","validationCode":"// only resize when no manifolds are pending\nif (AreAllManifoldStoresEmpty(contactEvents))\n    contactEvents.ResizeWorkerCount(newWorkerCount);","typeGuard":null,"tryCatchPattern":"try { contactEvents.ResizeWorkerCount(n); } catch (InvalidOperationException) { QueueResizeAfterFlush(n); }","preventionTips":["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"],"tags":["physics","lifecycle","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}