{"record":{"id":"126285b45b8da857","repo":"HangfireIO/Hangfire","slug":"monitoringapi-should-inherit-the-jobstoragemonito","errorCode":null,"errorMessage":"MonitoringApi should inherit the `JobStorageMonitor` class","messagePattern":"MonitoringApi should inherit the `JobStorageMonitor` class","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/Dashboard/Pages/AwaitingJobsPage.cshtml","lineNumber":31,"sourceCode":"@{\n    Layout = new LayoutPage(Strings.AwaitingJobsPage_Title);\n\n    int from, perPage;\n\n    int.TryParse(Query(\"from\"), out from);\n    int.TryParse(Query(\"count\"), out perPage);\n\n    List<string> jobIds = null;\n    Pager pager = null;\n    JobList <AwaitingJobDto> jobs = null;\n    int jobCount = 0;\n\n    if (Storage.HasFeature(JobStorageFeatures.Monitoring.AwaitingJobs))\n    {\n        var monitor = Storage.GetMonitoringApi() as JobStorageMonitor;\n        if (monitor == null) \n        {\n            throw new NotSupportedException(\"MonitoringApi should inherit the `JobStorageMonitor` class\");\n        }\n\n        pager = new Pager(from, perPage, DashboardOptions.DefaultRecordsPerPage, monitor.AwaitingCount());\n        jobs = monitor.AwaitingJobs(pager.FromRecord, pager.RecordsPerPage);\n        jobCount = jobs.Count;\n    }\n    else\n    {\n        using (var connection = Storage.GetReadOnlyConnection())\n        {\n            var storageConnection = connection as JobStorageConnection;\n\n            if (storageConnection != null)\n            {\n                pager = new Pager(from, perPage, DashboardOptions.DefaultRecordsPerPage, storageConnection.GetSetCount(\"awaiting\"));\n                jobIds = storageConnection.GetRangeFromSet(\"awaiting\", pager.FromRecord, pager.FromRecord + pager.RecordsPerPage - 1);\n                jobCount = jobIds.Count;\n            }","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/Dashboard/Pages/AwaitingJobsPage.cshtml#L13-L49","documentation":"The Awaiting Jobs dashboard page (AwaitingJobsPage.cshtml:31) checks whether the storage's monitoring API supports the awaiting-jobs feature. If JobStorageFeatures.Monitoring.AwaitingJobs is advertised but the monitoring API does not inherit from JobStorageMonitor, a NotSupportedException is thrown because the page needs to call monitor.AwaitingCount() and monitor.AwaitingJobs() which are defined on JobStorageMonitor.","triggerScenarios":"A custom JobStorage implementation declares the AwaitingJobs monitoring feature flag but its monitoring API class does not derive from JobStorageMonitor.","commonSituations":"Building a custom storage provider and incorrectly advertising the AwaitingJobs feature; upgrading Hangfire and the storage provider has not been updated to match the new feature surface.","solutions":["Make your custom MonitoringApi class inherit from JobStorageMonitor and implement AwaitingCount() and AwaitingJobs().","Do not advertise JobStorageFeatures.Monitoring.AwaitingJobs in your storage's feature set if the monitoring API does not support it.","Upgrade to a storage provider version that is compatible with the Hangfire.Core version in use."],"exampleFix":"// before\npublic class MyMonitoringApi : IMonitoringApi\n{\n    // missing AwaitingCount / AwaitingJobs\n}\n\n// after\npublic class MyMonitoringApi : JobStorageMonitor\n{\n    public override int AwaitingCount() { /* query storage */ }\n    public override JobList<AwaitingJobDto> AwaitingJobs(int from, int count) { /* query storage */ }\n}","handlingStrategy":"type-guard","validationCode":"var monitor = storage.GetMonitoringApi();\nif (!(monitor is JobStorageMonitor))\n    throw new InvalidOperationException(\n        \"Monitoring API must inherit JobStorageMonitor to use the Awaiting Jobs feature.\");","typeGuard":"static bool SupportsAwaitingJobs(JobStorage storage)\n{\n    if (!storage.HasFeature(JobStorageFeatures.Monitoring.AwaitingJobs)) return false;\n    return storage.GetMonitoringApi() is JobStorageMonitor;\n}","tryCatchPattern":null,"preventionTips":["When building a custom storage, derive MonitoringApi from JobStorageMonitor if you advertise AwaitingJobs.","Do not set JobStorageFeatures.Monitoring.AwaitingJobs unless the monitoring API actually supports it.","Keep storage provider versions in sync with Hangfire.Core."],"tags":["dashboard","storage-provider","feature-flag","notsupported"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}