{"record":{"id":"a7daba4332b86c5b","repo":"sschmid/Entitas","slug":"cannot-destroy-this","errorCode":null,"errorMessage":"Cannot destroy {this}!","messagePattern":"Cannot destroy (.+?)!","errorType":"exception","errorClass":"EntityIsNotEnabledException","httpStatus":null,"severity":"error","filePath":"src/Entitas/Entity/Entity.cs","lineNumber":367,"sourceCode":"\n        /// Releases the entity. An owner can only release an entity\n        /// if it retains it.\n        /// Retain/Release is part of AERC (Automatic Entity Reference Counting)\n        /// and is used internally to prevent pooling retained entities.\n        /// If you use retain manually you also have to\n        /// release it manually at some point.\n        public void Release(object owner)\n        {\n            _aerc.Release(owner);\n            if (_aerc.RetainCount == 0)\n                OnEntityReleased?.Invoke(this);\n        }\n\n        // Dispatches OnDestroyEntity which will start the destroy process.\n        public void Destroy()\n        {\n            if (!_isEnabled)\n                throw new EntityIsNotEnabledException($\"Cannot destroy {this}!\");\n\n            OnDestroyEntity?.Invoke(this);\n        }\n\n        // This method is used internally. Don't call it yourself.\n        // Use entity.Destroy();\n        public void InternalDestroy()\n        {\n            _isEnabled = false;\n            RemoveAllComponents();\n            OnComponentAdded = null;\n            OnComponentReplaced = null;\n            OnComponentRemoved = null;\n            OnDestroyEntity = null;\n        }\n\n        // Do not call this method manually. This method is called by the context.\n        public void RemoveAllOnEntityReleasedHandlers() => OnEntityReleased = null;","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/sschmid/Entitas/blob/37547d1bd280f3f1c1ef7edb44f2a206660fbfb4/src/Entitas/Entity/Entity.cs#L349-L385","documentation":"Thrown by Entity.Destroy when the entity is already destroyed/disabled. Destroy dispatches OnDestroyEntity; Entitas forbids destroying an entity twice because the destroy process (retainer release, component teardown, pool return) must run exactly once.","triggerScenarios":"Calling entity.Destroy() on an entity already destroyed; destroying in two systems in the same tick; destroying from a listener that itself was triggered by the destroy process; double cleanup in teardown code.","commonSituations":"Multiple reactive systems matching the same entity and each destroying it; application shutdown paths that destroy entities unconditionally; listener callbacks not unsubscribed before destroy.","solutions":["Guard with if (entity.isEnabled) entity.Destroy();","Ensure only one system owns the destroy decision for an entity class","Unsubscribe listeners in OnDestroyEntity handlers so post-destroy callbacks cannot call Destroy again","Use context.DestroyAllEntities() only once during teardown"],"exampleFix":"// before\nforeach (var e in _buffer) e.Destroy(); // may double-destroy\n// after\nforeach (var e in _buffer) {\n    if (e.isEnabled) {\n        e.Destroy();\n    }\n}","handlingStrategy":"validation","validationCode":"if (entity.isEnabled) entity.Destroy();","typeGuard":"bool CanDestroy(Entity e) => e.isEnabled;","tryCatchPattern":"try { entity.Destroy(); }\ncatch (EntityIsNotEnabledException) { /* already destroyed */ }","preventionTips":["Give one system sole responsibility for destroying each entity kind","Check isEnabled in shared destroy helpers","Unsubscribe from entity events before/at destroy","Avoid destroying from multiple reactive systems matching the same entities"],"tags":["csharp","entitas","entity-lifecycle","double-destroy"],"backgroundTag":"invalid-state-transition","analyzedSha":"37547d1bd280f3f1c1ef7edb44f2a206660fbfb4","analyzedAt":"2026-09-14T00:26:23.246Z","contentChangedAt":"2026-09-14T00:26:23.246Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}