dotnet/machinelearning · error · ObjectDisposedException
PoolLoader`1
Error message
PoolLoader`1
What it means
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>.
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
Example fix
// before: cached field private readonly PredictionEnginePool<MData,Pred> _pool; // disposed after hot-swap // after: resolve per use var engine = _serviceProvider.GetRequiredService<PredictionEnginePool<MData,Pred>>().GetPredictionEngine();
Defensive patterns
Strategy: try-catch
Validate before calling
// check pool liveness via DI resolution each use, not a cached field
Type guard
null
Try / catch
try { var engine = pool.Get(); } catch (ObjectDisposedException) { pool = serviceProvider.GetRequiredService<PredictionEnginePool<TData,TPred>>(); var engine = pool.Get(); } Prevention
- Don't cache PredictionEnginePool references across model hot-swaps
- Keep rented engine lifetimes short (rent, predict, return)
- Cancel background prediction loops on host shutdown
When it happens
Trigger: 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.
Common situations: App long-lived code caching a reference to PredictionEnginePool across a model file update; DI container disposed while background code still calls Get.
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
- PredictionEnginePool`2
- engine (Parameter 'engine')
- engine (Parameter 'engine')
- Object is disposed.
- Start must be called on a ModelLoader before it can be used.
AI-assisted analysis of dotnet/machinelearning@7b76e69cf9 (2026-09-11).
Data as JSON: /api/errors/449630977504bff1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.Extensions.ML/PoolLoader.cs:65
public ModelLoader Loader { get; }
private MLContext Context { get; }
/// <summary>
/// The active pool generation. Exposed for compatibility; prefer <see cref="Get"/> and
/// <see cref="Return"/>, which route an engine back to the generation that created it.
/// </summary>
public ObjectPool<PredictionEngine<TData, TPrediction>> PredictionEnginePool { get { return Volatile.Read(ref _pool); } }
/// <summary>
/// Rents an engine from the current pool generation, recording its origin so it can be
/// returned to the correct generation later.
/// </summary>
public PredictionEngine<TData, TPrediction> Get()
{
var pool = Volatile.Read(ref _pool);
if (Volatile.Read(ref _disposed) != 0 || pool == null)
{
throw new ObjectDisposedException(nameof(PoolLoader<TData, TPrediction>));
}
var engine = pool.Get();
_rentedEngines.Remove(engine);
_rentedEngines.Add(engine, pool);
return engine;
}
/// <summary>
/// Returns an engine to the generation it was rented from. If that generation has already
/// been disposed by a hot-swap, the pool disposes the engine instead of retaining it.
/// </summary>
public void Return(PredictionEngine<TData, TPrediction> engine)
{
if (engine == null)
{
throw new ArgumentNullException(nameof(engine));View on GitHub (pinned to 7b76e69cf9)