{"record":{"id":"449630977504bff1","repo":"dotnet/machinelearning","slug":"poolloader-1","errorCode":null,"errorMessage":"PoolLoader`1","messagePattern":"PoolLoader`1","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Microsoft.Extensions.ML/PoolLoader.cs","lineNumber":65,"sourceCode":"        public ModelLoader Loader { get; }\n        private MLContext Context { get; }\n\n        /// <summary>\n        /// The active pool generation. Exposed for compatibility; prefer <see cref=\"Get\"/> and\n        /// <see cref=\"Return\"/>, which route an engine back to the generation that created it.\n        /// </summary>\n        public ObjectPool<PredictionEngine<TData, TPrediction>> PredictionEnginePool { get { return Volatile.Read(ref _pool); } }\n\n        /// <summary>\n        /// Rents an engine from the current pool generation, recording its origin so it can be\n        /// returned to the correct generation later.\n        /// </summary>\n        public PredictionEngine<TData, TPrediction> Get()\n        {\n            var pool = Volatile.Read(ref _pool);\n            if (Volatile.Read(ref _disposed) != 0 || pool == null)\n            {\n                throw new ObjectDisposedException(nameof(PoolLoader<TData, TPrediction>));\n            }\n\n            var engine = pool.Get();\n\n            _rentedEngines.Remove(engine);\n            _rentedEngines.Add(engine, pool);\n            return engine;\n        }\n\n        /// <summary>\n        /// Returns an engine to the generation it was rented from. If that generation has already\n        /// been disposed by a hot-swap, the pool disposes the engine instead of retaining it.\n        /// </summary>\n        public void Return(PredictionEngine<TData, TPrediction> engine)\n        {\n            if (engine == null)\n            {\n                throw new ArgumentNullException(nameof(engine));","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/dotnet/machinelearning/blob/7b76e69cf964daeca3f1377af6bc5543284d56c6/src/Microsoft.Extensions.ML/PoolLoader.cs#L47-L83","documentation":"PoolLoader.Get() rents a PredictionEngine from its internal pool. If the loader was disposed (hot-swap or pool shutdown set _disposed) or the pool object is gone, it throws ObjectDisposedException named after PoolLoader<TData,TPrediction>.","triggerScenarios":"Calling Get() after the PredictionEnginePool was disposed (e.g. after a model hot-swap replaced the pool, or after host shutdown); holding a rented engine across a model reload then calling Get() again.","commonSituations":"App long-lived code caching a reference to PredictionEnginePool across a model file update; DI container disposed while background code still calls Get.","solutions":["Resolve PredictionEnginePool through DI fresh each time instead of caching it across hot-swaps","Catch ObjectDisposedException and re-resolve the pool","Ensure the host/pool outlives all code that rents engines"],"exampleFix":"// before: cached field\nprivate readonly PredictionEnginePool<MData,Pred> _pool; // disposed after hot-swap\n// after: resolve per use\nvar engine = _serviceProvider.GetRequiredService<PredictionEnginePool<MData,Pred>>().GetPredictionEngine();","handlingStrategy":"try-catch","validationCode":"// check pool liveness via DI resolution each use, not a cached field","typeGuard":"null","tryCatchPattern":"try { var engine = pool.Get(); } catch (ObjectDisposedException) { pool = serviceProvider.GetRequiredService<PredictionEnginePool<TData,TPred>>(); var engine = pool.Get(); }","preventionTips":["Don't cache PredictionEnginePool references across model hot-swaps","Keep rented engine lifetimes short (rent, predict, return)","Cancel background prediction loops on host shutdown"],"tags":["object-disposed","pooling","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"7b76e69cf964daeca3f1377af6bc5543284d56c6","analyzedAt":"2026-09-11T12:35:38.930Z","contentChangedAt":"2026-09-11T12:35:38.930Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}