{"record":{"id":"d9f4f831915d420d","repo":"stride3d/stride","slug":"cannot-release-an-object-that-doesn-t-have-active-reference","errorCode":null,"errorMessage":"Cannot release an object that doesn't have active reference. AddReference/Release pair must match.","messagePattern":"Cannot release an object that doesn't have active reference\\. AddReference/Release pair must match\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core/DisposeBase.cs","lineNumber":87,"sourceCode":"            throw new InvalidOperationException(FrameworkResources.AddReferenceError);\n\n        return newCounter;\n    }\n\n    /// <inheritdoc/>\n    int IReferencable.Release()\n    {\n        OnReleaseReference();\n\n        var newCounter = Interlocked.Decrement(ref refCount);\n        if (newCounter == 0)\n        {\n            Destroy();\n            IsDisposed = true;\n        }\n        else if (newCounter < 0)\n        {\n            throw new InvalidOperationException(FrameworkResources.ReleaseReferenceError);\n        }\n        return newCounter;\n    }\n\n    /// <summary>\n    ///   Called when a new reference of this object has been counted (via a call to <see cref=\"IReferencable.AddReference\"/>).\n    /// </summary>\n    protected virtual void OnAddReference() { }\n\n    /// <summary>\n    ///   Called when a call to <see cref=\"IReferencable.Release\"/> has decremented the reference count of this object.\n    /// </summary>\n    protected virtual void OnReleaseReference() { }\n}\n","sourceCodeStart":69,"sourceCodeEnd":102,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core/DisposeBase.cs#L69-L102","documentation":"Release() decrements the reference counter atomically; if the resulting counter is negative, the caller has released more times than it acquired. The library throws InvalidOperationException to flag the unbalanced AddReference/Release pair before the corrupted counter causes worse failures. Every Release must correspond to exactly one prior AddReference.","triggerScenarios":"Calling IReferencable.Release() more times than AddReference() was called on the same object — e.g. an extra Release in an error/cleanup path, double-disposal, or calling Release on a never-referenced object.","commonSituations":"Cleanup code that releases unconditionally in a finally block after an earlier release already ran; wrapping code that both disposes and releases; sharing objects between systems where one side also releases.","solutions":["Find the extra Release call and remove it, or guard it so it only runs when that code path actually owns a reference","Track reference ownership explicitly: only call Release on objects your component AddReference'd itself","Check whether Dispose/DisposeMember is also releasing, causing a double decrement, and restructure ownership","Add logging in OnRelease overrides to trace the count per call site during development"],"exampleFix":"// before\nfinally\n{\n    texture.Release(); // may run after texture was already released on the error path above\n}\n// after\nfinally\n{\n    if (!released)\n    {\n        texture.Release();\n        released = true;\n    }\n}","handlingStrategy":"validation","validationCode":"if (obj is IReferencable r && r.RefCount > 0)\n{\n    r.Release();\n}","typeGuard":"static bool OwnsReference(DisposeBase obj) =>\n    obj is IReferencable && obj.RefCount > 0 && !obj.IsDisposed;","tryCatchPattern":"try\n{\n    ((IReferencable)obj).Release();\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"doesn't have active reference\"))\n{\n    // unbalanced Release: log and skip; do not retry the release\n}","preventionTips":["Only release references your component explicitly acquired via AddReference","Set an ownership flag/disposed flag so Release cannot run twice on the same path","Beware that Dispose may itself release member references — do not double-release","Trace refCount transitions in debug builds via OnAddReference/OnRelease overrides"],"tags":["csharp","reference-counting","object-lifetime","invalid-operation"],"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"}