EllanJiang/GameFramework · error · GameFrameworkException
The reference has been released.
Error message
The reference has been released.
What it means
ReferencePool.ReferenceCollection.Release returns a reference to the pool for reuse. With strict checking enabled (m_EnableStrictCheck), the collection verifies the reference is not already sitting in its free list before enqueueing; if it is, the same reference was released twice, and the framework throws rather than corrupting the pool with a duplicate entry that could be handed out to two owners.
Solutions
- Find and remove the duplicate Release call — release each acquired reference exactly once, from a single owner.
- Null out or mark the field holding the reference after Release so a second release path cannot reach it.
- Temporarily keep strict checking enabled during development to catch double-releases early; do not simply disable it to silence the error in production.
Example fix
// before ReferencePool.Release(reference); Cleanup(); // Cleanup also calls Release(reference) -> double release // after ReferencePool.Release(reference); reference = null; Cleanup(); // guard: if (reference != null) Release
Defensive patterns
Strategy: validation
Validate before calling
// keep a released-flag or null the field immediately: if (reference == null || reference.IsReleased) return; // caller-side bookkeeping ReferencePool.Release(reference); reference = null;
Type guard
bool CanRelease<T>(T r) where T : class, IReference => r != null && !releasedTracker.Contains(r);
Try / catch
try { ReferencePool.Release(reference); }
catch (GameFrameworkException ex) when (ex.Message.Contains("has been released"))
{
// double release — log stack of both release sites; make second release a no-op
} Prevention
- Null the reference field immediately after Release so cleanup paths cannot release it twice.
- Assign a single owner responsible for releasing each pooled reference.
- Keep EnableStrictCheck on in development builds to surface double-releases early.
When it happens
Trigger: Calling ReferencePool.Release(reference) twice for the same instance — e.g. both the owner and a cleanup routine release it, or a double-dispose path (explicit release plus a parent/manager release) — while ReferencePool.EnableStrictCheck is true.
Common situations: Double-free bugs in entity/component lifecycles where both the spawner and the scene teardown call Release; exception paths that release a reference and then a finally block releases it again; clear-all logic that releases references still tracked elsewhere.
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
- Type is invalid.
- Reference is invalid.
- Reference type is invalid.
- Reference type is not a non-abstract class type.
- Reference type ' ' is invalid.
AI-assisted analysis of EllanJiang/GameFramework@d0c010b051 (2026-09-15).
Data as JSON: /api/errors/553cba2a9d33dcb6.
Report an issue: GitHub.
Appendix: source
Thrown at GameFramework/Base/ReferencePool/ReferencePool.ReferenceCollection.cs:136
{
if (m_References.Count > 0)
{
return m_References.Dequeue();
}
}
m_AddReferenceCount++;
return (IReference)Activator.CreateInstance(m_ReferenceType);
}
public void Release(IReference reference)
{
reference.Clear();
lock (m_References)
{
if (m_EnableStrictCheck && m_References.Contains(reference))
{
throw new GameFrameworkException("The reference has been released.");
}
m_References.Enqueue(reference);
}
m_ReleaseReferenceCount++;
m_UsingReferenceCount--;
}
public void Add<T>(int count) where T : class, IReference, new()
{
if (typeof(T) != m_ReferenceType)
{
throw new GameFrameworkException("Type is invalid.");
}
lock (m_References)
{View on GitHub (pinned to d0c010b051)