microsoft/FASTER · error · FasterException

Getting handle in disposed device

Error message

Getting handle in disposed device

What it means

AsyncPool is a lightweight handle pool used internally by devices. Once the pool (backing device) has been disposed, Get can no longer hand out handles, so it throws to prevent using resources backed by a torn-down device.

Solutions

  1. Ensure all I/O (reads, writes, checkpoints, log iteration) completes before disposing the device/store.
  2. Keep the FASTER instance alive as long as any session or background operation can use the device.
  3. Guard shutdown with synchronization so Dispose happens after all worker threads finish.
  4. Catch FasterException at the I/O call site during shutdown to handle in-flight calls gracefully.

Example fix

// before
fht.Dispose();
device.Dispose();
backgroundWriter.Join();
// after
backgroundWriter.Join();
fht.Dispose();
device.Dispose();
Defensive patterns

Strategy: try-catch

Try / catch

try
{
    var item = pool.Get(token);
}
catch (FasterException) when (disposed) // or ObjectDisposedException around device usage
{
    throw new OperationCanceledException("Device disposed during shutdown");
}

Prevention

When it happens

Trigger: Calling pool.Get() (directly or indirectly through device read/write paths) after Dispose() was called on the device or the pool itself.

Common situations: Shutting down FASTER / disposing a device while background flush or checkpoint operations are still issuing I/O; use-after-dispose races between an application thread and a cleanup path.

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


AI-assisted analysis of microsoft/FASTER@321d872eab (2026-09-15). Data as JSON: /api/errors/ce05cae303f4d046. Report an issue: GitHub.

Appendix: source

Thrown at cs/src/core/Device/AsyncPool.cs:49

        public AsyncPool(int size, Func<T> creator)
        {
            this.size = size;
            this.creator = creator;
            this.handleAvailable = new SemaphoreSlim(0);
            this.itemQueue = new ConcurrentQueue<T>();
        }

        /// <summary>
        /// Get item synchronously
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public T Get(CancellationToken token = default)
        {
            for (; ; )
            {
                if (disposed)
                    throw new FasterException("Getting handle in disposed device");

                if (GetOrAdd(itemQueue, out T item))
                    return item;

                handleAvailable.Wait(token);
            }
        }

        /// <summary>
        /// Get item asynchronously
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async ValueTask<T> GetAsync(CancellationToken token = default)
        {
            for (; ; )
            {
                if (disposed)

View on GitHub (pinned to 321d872eab)