{"record":{"id":"4a8ebf7d718e112e","repo":"sschmid/Entitas","slug":"entityisnotretainedbyownerexception-entity-owner","errorCode":null,"errorMessage":"EntityIsNotRetainedByOwnerException(_entity, owner)","messagePattern":"EntityIsNotRetainedByOwnerException\\(_entity, owner\\)","errorType":"exception","errorClass":"EntityIsNotRetainedByOwnerException","httpStatus":null,"severity":"error","filePath":"src/Entitas/Entity/SafeAERC.cs","lineNumber":37,"sourceCode":"\n        readonly Entity _entity;\n        readonly HashSet<object> _owners = new HashSet<object>();\n\n        public SafeAERC(Entity entity)\n        {\n            _entity = entity;\n        }\n\n        public void Retain(object owner)\n        {\n            if (!Owners.Add(owner))\n                throw new EntityIsAlreadyRetainedByOwnerException(_entity, owner);\n        }\n\n        public void Release(object owner)\n        {\n            if (!Owners.Remove(owner))\n                throw new EntityIsNotRetainedByOwnerException(_entity, owner);\n        }\n    }\n}\n","sourceCodeStart":19,"sourceCodeEnd":41,"githubUrl":"https://github.com/sschmid/Entitas/blob/37547d1bd280f3f1c1ef7edb44f2a206660fbfb4/src/Entitas/Entity/SafeAERC.cs#L19-L41","documentation":"Thrown by SafeAERC.Release when the given owner does not currently retain the entity (Owners.Remove returns false). Every Release must be paired with a prior Retain by the same owner; releasing unbalanced would drop someone else's reference count.","triggerScenarios":"Calling entity.Release(owner) without a matching earlier Retain(owner); releasing twice; a teardown path that releases entities never retained; releasing after the retain bookkeeping was reset.","commonSituations":"Destroy handlers releasing entities retained elsewhere; systems destroyed before they retained; mixed use of UnsafeAERC/SafeAERC where retains were not recorded.","solutions":["Ensure Retain(owner) was called before Release(owner) — pair them in acquire/remove code paths","Guard release logic with entity.Owners.Contains(owner) (SafeAERC) before releasing","Keep retention symmetric: retain in add-to-collection, release in remove-from-collection","Audit Retain/Release call sites to confirm the same owner instance is used"],"exampleFix":"// before\nvoid OnEntityRemoved(Entity e) { e.Release(this); _list.Remove(e); } // throws if never retained\n// after\nvoid OnEntityRemoved(Entity e) {\n    if (_list.Remove(e)) {\n        e.Release(this);\n    }\n}","handlingStrategy":"validation","validationCode":"if (entity.Aerc is SafeAERC sa && sa.Owners.Contains(owner)) entity.Release(owner);","typeGuard":"bool CanRelease(Entity e, object owner) => e.Aerc is SafeAERC sa && sa.Owners.Contains(owner);","tryCatchPattern":"try { entity.Release(owner); }\ncatch (EntityIsNotRetainedByOwnerException) { /* never retained by this owner */ }","preventionTips":["Only release owners you previously retained","Tie Release to removal from the collection that performed the Retain","Use the same owner instance everywhere (typically 'this')"],"tags":["csharp","entitas","retention","aerc"],"backgroundTag":"internal-invariant-violation","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"}