sschmid/Entitas · error · EntityIsAlreadyRetainedByOwnerException
EntityIsAlreadyRetainedByOwnerException(_entity, owner)
Error message
EntityIsAlreadyRetainedByOwnerException(_entity, owner)
What it means
Thrown by SafeAERC.Retain when the given owner already retains the entity. SafeAERC (safe automatic entity retention control) tracks a set of owners; Owners.Add returns false if the owner is already present, which means Retain was called twice for the same owner — an unbalanced retain that would leak the entity.
Solutions
- Track retention yourself: only call Retain if the entity was not already retained by that owner
- Call Release(owner) symmetrically in the corresponding teardown/callback path
- Retain once at acquisition (e.g. when adding to your collection) and release at removal
- Switch to UnsafeAERC only if you fully control retention and accept no safety checks
Example fix
// before
void OnEntityAdded(Entity e) { e.Retain(this); _list.Add(e); } // duplicates possible
// after
void OnEntityAdded(Entity e) {
if (!_list.Contains(e)) {
e.Retain(this);
_list.Add(e);
}
} Defensive patterns
Strategy: validation
Validate before calling
if (entity.Aerc is SafeAERC sa && !sa.Owners.Contains(owner)) entity.Retain(owner);
Type guard
bool CanRetain(Entity e, object owner) => e.Aerc is SafeAERC sa ? !sa.Owners.Contains(owner) : true;
Try / catch
try { entity.Retain(owner); }
catch (EntityIsAlreadyRetainedByOwnerException) { /* already retained by this owner */ } Prevention
- Retain exactly once per owner, at acquisition time
- Keep Retain/Release symmetric in add/remove pairs
- Deduplicate events before retaining in handlers
When it happens
Trigger: Calling entity.Retain(owner) twice with the same owner object without an intervening Release(owner); retaining in a handler that can fire repeatedly for the same entity.
Common situations: System retaining entities on every OnEntityAdded event including duplicates; re-entrant initialization running Retain twice; retaining in both a constructor and an OnEntityAdded handler.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- EntityIsNotRetainedByOwnerException(_entity, owner)
- Cannot remove component
- Cannot replace component
- Cannot get component
- Cannot destroy !
AI-assisted analysis of sschmid/Entitas@37547d1bd2 (2026-09-14).
Data as JSON: /api/errors/514ccb6e1b1bed6b.
Report an issue: GitHub.
Appendix: source
Thrown at src/Entitas/Entity/SafeAERC.cs:31
public sealed class SafeAERC : IAERC
{
public static readonly Func<Entity, IAERC> Delegate = entity => new SafeAERC(entity);
public int RetainCount => _owners.Count;
public HashSet<object> Owners => _owners;
readonly Entity _entity;
readonly HashSet<object> _owners = new HashSet<object>();
public SafeAERC(Entity entity)
{
_entity = entity;
}
public void Retain(object owner)
{
if (!Owners.Add(owner))
throw new EntityIsAlreadyRetainedByOwnerException(_entity, owner);
}
public void Release(object owner)
{
if (!Owners.Remove(owner))
throw new EntityIsNotRetainedByOwnerException(_entity, owner);
}
}
}
View on GitHub (pinned to 37547d1bd2)