{"record":{"id":"2a48bc91b1416094","repo":"stride3d/stride","slug":"the-object-must-be-idisposable-ireferenceable-or-intptr","errorCode":null,"errorMessage":"The object must be IDisposable, IReferenceable, or IntPtr","messagePattern":"The object must be IDisposable, IReferenceable, or IntPtr","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core/ObjectCollector.cs","lineNumber":62,"sourceCode":"    {\n        disposables ??= [];\n    }\n\n    /// <summary>\n    ///   Adds an object implementing the <see cref=\"IDisposable\"/> or <see cref=\"IReferencable\"/> interfaces,\n    ///   or a <see cref=\"IntPtr\"/> to an object allocated using <see cref=\"MemoryUtilities.Allocate\"/>\n    ///   to the list of the objects to dispose.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the object to add.</typeparam>\n    /// <param name=\"objectToDispose\">The object to add to the collector to be disposed at a later time.</param>\n    /// <exception cref=\"ArgumentException\">\n    ///   <paramref name=\"objectToDispose\"/> does not implement the interface <see cref=\"IDisposable\"/>, <see cref=\"IReferencable\"/>,\n    ///   and is not a valid memory pointer allocated by <see cref=\"MemoryUtilities.Allocate\"/>.\n    /// </exception>\n    public T Add<T>(T objectToDispose) where T : notnull\n    {\n        if (objectToDispose is not (IDisposable or IReferencable or IntPtr))\n            throw new ArgumentException(\"The object must be IDisposable, IReferenceable, or IntPtr\", nameof(objectToDispose));\n\n        // Check memory alignment\n        if (objectToDispose is IntPtr memoryPtr && !MemoryUtilities.IsAligned(memoryPtr))\n            throw new ArgumentException(\"The memory pointer is invalid. Memory must have been allocated with MemoryUtilities.Allocate\", nameof(objectToDispose));\n\n        EnsureValid();\n\n        if (!disposables.Contains(objectToDispose))\n            disposables.Add(objectToDispose);\n\n        return objectToDispose;\n    }\n\n    /// <summary>\n    ///   Removes a disposable object from the list of the objects to dispose.\n    /// </summary>\n    /// <typeparam name=\"T\">The type of the object to remove.</typeparam>\n    /// <param name=\"objectToDispose\">The object to be removed from the list of objects to dispose.</param>","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core/ObjectCollector.cs#L44-L80","documentation":"ObjectCollector.Add<T> only accepts objects that are IDisposable, implement IReferencable, or are an IntPtr memory handle, because it must know how to release them during disposal. Passing any other object type is rejected with this ArgumentException to keep the collector's cleanup contract sound.","triggerScenarios":"Calling collector.Add(someObject) where someObject's runtime type implements none of IDisposable, IReferencable, and is not an IntPtr.","commonSituations":"Registering plain POCOs or service objects in a ComponentBase/Dispose collector by mistake; refactors that drop IDisposable from a registered class; wrapping a resource in a non-disposable adapter.","solutions":["Make the registered type implement IDisposable and put its cleanup in Dispose().","If it wraps native memory, register the IntPtr handle allocated via MemoryUtilities.Allocate instead.","If it is a reference-counted Stride object, implement/inherit IReferencable.","If the object needs no cleanup, do not register it in the collector."],"exampleFix":"// before\ncollector.Add(new ConfigSnapshot()); // not IDisposable\n// after\nclass ConfigSnapshot : IDisposable { public void Dispose() { ... } }\ncollector.Add(new ConfigSnapshot());","handlingStrategy":"type-guard","validationCode":"if (obj is not IDisposable and not IReferencable and not IntPtr)\n    throw new InvalidOperationException(\"Object is not registrable in ObjectCollector\");","typeGuard":"static bool IsCollectible<T>(T o) where T : notnull => o is IDisposable or IReferencable or IntPtr;","tryCatchPattern":"try { collector.Add(obj); }\ncatch (ArgumentException ex) when (ex.ParamName == \"objectToDispose\")\n{\n    // object type not managed by the collector; handle or register a wrapper\n}","preventionTips":["Only pass IDisposable, IReferencable, or MemoryUtilities-allocated IntPtr values to Add.","Make resource wrapper classes implement IDisposable by convention.","Keep POCOs out of dispose collectors; use a plain list for those."],"tags":["argument-exception","disposal","object-collector"],"backgroundTag":"invalid-argument-value","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}