{"record":{"id":"3d77868c2a0423ad","repo":"HangfireIO/Hangfire","slug":"gettype-fullname","errorCode":null,"errorMessage":"{GetType().FullName}","messagePattern":"\\{GetType\\(\\)\\.FullName\\}","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Processing/BackgroundTaskScheduler.cs","lineNumber":347,"sourceCode":"                handler?.Invoke(exception);\n            }\n#if !NETSTANDARD1_3\n            catch (Exception ex) when (ex.IsCatchableExceptionType())\n            {\n                Trace.WriteLine(\"Unexpected exception caught in exception handler itself.\" + Environment.NewLine + ex);\n            }\n#else\n            catch\n            {\n            }\n#endif\n        }\n\n        private void ThrowIfDisposed()\n        {\n            if (Volatile.Read(ref _disposed) == 1)\n            {\n                throw new ObjectDisposedException(GetType().FullName);\n            }\n        }\n    }\n}\n","sourceCodeStart":329,"sourceCodeEnd":352,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Processing/BackgroundTaskScheduler.cs#L329-L352","documentation":"Thrown by BackgroundTaskScheduler.ThrowIfDisposed (an ObjectDisposedException with the type's full name) when an operation is attempted after Dispose(). The scheduler sets _disposed=1 in Dispose() and releases its wait handles; continued use after that is undefined.","triggerScenarios":"Calling GetScheduledTasks (or any path through ThrowIfDisposed) on a BackgroundTaskScheduler after Dispose() was invoked. Commonly a shutdown race where one thread disposes while another queries scheduled tasks.","commonSituations":"Application shutdown disposes the scheduler while a diagnostics/monitoring thread enumerates scheduled tasks; a using-block scopes the scheduler too narrowly; double-handling where Dispose runs early due to an exception.","solutions":["Stop all consumers of the scheduler before calling Dispose(); use a cancellation token to wind down worker queries.","Catch ObjectDisposedException at call sites that may race with shutdown and treat it as 'no tasks'.","Avoid calling GetScheduledTasks for diagnostics on a scheduler that may be disposed — snapshot liveness another way."],"exampleFix":"// before\nvar tasks = scheduler.GetScheduledTasks(); // throws if disposed\n\n// after\nIEnumerable<Task> tasks;\ntry { tasks = scheduler.GetScheduledTasks(); }\ncatch (ObjectDisposedException) { tasks = Enumerable.Empty<Task>(); }","handlingStrategy":"try-catch","validationCode":"if (_disposed == 1) return Enumerable.Empty<Task>();\nreturn scheduler.GetScheduledTasks();","typeGuard":null,"tryCatchPattern":"IEnumerable<Task> tasks;\ntry { tasks = scheduler.GetScheduledTasks(); }\ncatch (ObjectDisposedException) { tasks = Enumerable.Empty<Task>(); }","preventionTips":["Tear down all consumers (diagnostics, monitors) before disposing the scheduler.","Use a cancellation token to signal shutdown so queries stop before Dispose().","Never query a scheduler whose lifetime is owned by a using-block."],"tags":["hangfire","object-disposed","task-scheduler","threading","lifecycle"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}