{"record":{"id":"195aa5d961141aaa","repo":"Unity-Technologies/UnityCsReference","slug":"not-a-valid-handle-has-it-been-released-already","errorCode":null,"errorMessage":"Not a valid handle, has it been released already?","messagePattern":"Not a valid handle, has it been released already\\?","errorType":"exception","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"Editor/Mono/ChangeTrackerHandle.bindings.cs","lineNumber":94,"sourceCode":"        internal extern bool HasModifiedTrackedPropertiesInternal();\n\n        [NativeName(\"GetModifiedTrackedProperties\")]\n        private extern SerializedProperty[] GetModifiedTrackedPropertiesInternal();\n\n        [NativeName(\"ClearModifiedTrackedProperties\")]\n        private extern void ClearModifiedTrackedPropertiesInternal();\n\n        [FreeFunction(\"SerializedObjectChangeTracker::AcquireTracker\")]\n        private static extern IntPtr Internal_AcquireTracker(UnityEditor.SerializedObject o);\n\n        [FreeFunction(\"SerializedObjectChangeTracker::ReleaseTracker\", IsThreadSafe = true)]\n        private static extern void Internal_ReleaseTracker(IntPtr handle);\n\n        // returns true if object changed since last poll\n        internal bool PollForChanges(bool updateSerializedObject)\n        {\n            if (m_Handle == IntPtr.Zero)\n                throw new ArgumentNullException(\"Not a valid handle, has it been released already?\");\n            bool result = Internal_PollChanges(updateSerializedObject);\n\n            if (HasModifiedTrackedPropertiesInternal())\n            {\n                m_ModifiedTrackedProperties = GetModifiedTrackedPropertiesInternal();\n                for (int i = 0; i < m_ModifiedTrackedProperties.Length; ++i)\n                {\n                    m_ModifiedTrackedProperties[i].m_SerializedObject = m_SerializedObject;\n                }\n\n                ClearModifiedTrackedPropertiesInternal();\n            }\n            else\n            {\n                m_ModifiedTrackedProperties = s_EmptyPropertyArray;\n            }\n\n            return result;","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/Unity-Technologies/UnityCsReference/blob/225b0fbdb57cc17d094e8056b71f8314aba56f73/Editor/Mono/ChangeTrackerHandle.bindings.cs#L76-L112","documentation":"Thrown as ArgumentNullException (mis-typed exception; semantically an invalid-handle error) by ChangeTrackerHandle.PollForChanges when m_Handle == IntPtr.Zero. The handle is acquired via Internal_AcquireTracker and released via Internal_ReleaseTracker; after release the field is zeroed and any further polling is invalid. The message asks whether ReleaseTracker already ran.","triggerScenarios":"Calling tracker.PollForChanges(updateSerializedObject) after Internal_ReleaseTracker has been called on the handle (or after the tracker was never acquired). Also possible if the tracker object is reused after being released by the SerializedObjectChangeTracker native side.","commonSituations":"Editor inspection tooling that caches a ChangeTrackerHandle and polls across editor events, then releases the handle but keeps polling on a stale reference. Domain reload invalidating the native handle while the managed wrapper persists. Code paths that release on one event and poll on the next.","solutions":["Stop calling PollForChanges after ReleaseTracker; null/track the released state on the managed side.","Wrap tracker usage in a using/IDisposable pattern so release and last-use cannot be reordered.","After release, set the managed field holding the tracker to null and null-check before polling."],"exampleFix":"// before\ntracker.Release();\n...\ntracker.PollForChanges(true);\n\n// after\ntracker.Release();\ntracker = null;\n...\nif (tracker != null) tracker.PollForChanges(true);","handlingStrategy":"validation","validationCode":"if (tracker == null || tracker.handle == IntPtr.Zero) return;\ntracker.PollForChanges(updateSerializedObject);","typeGuard":null,"tryCatchPattern":"try { tracker.PollForChanges(updateSerializedObject); }\ncatch (ArgumentNullException) { /* handle already released; re-acquire */ }","preventionTips":["Null the managed reference after Release.","Use a using/IDisposable scope for the tracker.","Never poll after release."],"tags":["unity-editor","serialized-object","native-handle","lifecycle","argument-validation"],"backgroundTag":null,"analyzedSha":"225b0fbdb57cc17d094e8056b71f8314aba56f73","analyzedAt":"2026-08-13T19:07:19.849Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}