{"record":{"id":"2ca78f268844694e","repo":"HangfireIO/Hangfire","slug":"current-storage-doesn-t-support-specifying-queues-2ca78f","errorCode":null,"errorMessage":"Current storage doesn't support specifying queues directly for a specific job. Please use the QueueAttribute instead.","messagePattern":"Current storage doesn't support specifying queues directly for a specific job\\. Please use the QueueAttribute instead\\.","errorType":"exception","errorClass":"NotSupportedException","httpStatus":null,"severity":"error","filePath":"src/Hangfire.Core/RecurringJobManager.cs","lineNumber":108,"sourceCode":"            _factory = factory ?? throw new ArgumentNullException(nameof(factory));\n            _timeZoneResolver = timeZoneResolver ?? throw new ArgumentNullException(nameof(timeZoneResolver));\n            _nowFactory = nowFactory ?? throw new ArgumentNullException(nameof(nowFactory));\n        }\n\n        public JobStorage Storage => _storage;\n\n        public void AddOrUpdate(string recurringJobId, Job job, string cronExpression, RecurringJobOptions options)\n        {\n            if (recurringJobId == null) throw new ArgumentNullException(nameof(recurringJobId));\n            if (job == null) throw new ArgumentNullException(nameof(job));\n            if (cronExpression == null) throw new ArgumentNullException(nameof(cronExpression));\n            if (options == null) throw new ArgumentNullException(nameof(options));\n\n            ValidateCronExpression(cronExpression);\n\n            if (job.Queue != null && !Storage.HasFeature(JobStorageFeatures.JobQueueProperty))\n            {\n                throw new NotSupportedException(\"Current storage doesn't support specifying queues directly for a specific job. Please use the QueueAttribute instead.\");\n            }\n\n            using (var connection = _storage.GetConnection())\n            using (connection.AcquireDistributedRecurringJobLock(recurringJobId, DefaultTimeout))\n            {\n                var now = _nowFactory();\n                var recurringJob = connection.GetOrCreateRecurringJob(recurringJobId);\n                var scheduleChanged = false;\n\n                recurringJob.Job = InvocationData.SerializeJob(job).SerializePayload();\n\n                if (!cronExpression.Equals(recurringJob.Cron, StringComparison.OrdinalIgnoreCase))\n                {\n                    recurringJob.Cron = cronExpression;\n                    scheduleChanged = true;\n                }\n\n                if (!options.TimeZone.Id.Equals(recurringJob.TimeZoneId, StringComparison.OrdinalIgnoreCase))","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/HangfireIO/Hangfire/blob/c236dd0f930f831ec151e436e138ddc429a02a72/src/Hangfire.Core/RecurringJobManager.cs#L90-L126","documentation":"Thrown by RecurringJobManager.AddOrUpdate when a Job has a Queue set but the configured JobStorage does not advertise the JobQueueProperty feature (JobStorageFeatures.JobQueueProperty = \"Job.Queue\"). Per-job queue targeting is an opt-in storage capability; storages that don't support it must use the QueueAttribute or default queue instead.","triggerScenarios":"Creating a Job with a non-null Queue (via Job.FromExpression with QueueAttribute, or by setting Job.Queue) and calling AddOrUpdate against a storage that doesn't report the Job.Queue feature — typically the in-memory storage or a minimal custom storage.","commonSituations":"Using [Queue(\"critical\")] on a method and registering it as a recurring job while backed by a storage without queue-property support (e.g. MemoryStorage in older versions, or a custom storage). Mixing a queue-aware job definition with a storage that only supports the default queue.","solutions":["Remove the per-job Queue / [Queue] attribute so the job uses the default queue on this storage.","Switch to a storage that supports JobQueueProperty (e.g. SqlServer, Redis) when per-job queue routing is required.","If building a custom storage, implement HasFeature to return true for JobStorageFeatures.JobQueueProperty and support the queue on enqueue."],"exampleFix":"// before\n[Queue(\"critical\")]\npublic static void Work() { }\nRecurringJob.AddOrUpdate(\"j\", () => Work(), Cron.Daily()); // unsupported storage\n\n// after — remove per-job queue on unsupported storage\npublic static void Work() { }\nRecurringJob.AddOrUpdate(\"j\", () => Work(), Cron.Daily());","handlingStrategy":"validation","validationCode":"if (job.Queue != null && !JobStorage.Current.HasFeature(JobStorageFeatures.JobQueueProperty))\n{\n    throw new InvalidOperationException(\"This storage cannot route per-job queues; remove the Queue attribute.\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check storage capabilities before using [Queue] on jobs.","Use a queue-aware storage (SqlServer, Redis) when per-job queue routing is needed.","For custom storages, implement HasFeature(JobQueueProperty) truthfully."],"tags":["recurring-job","storage-features","queue","not-supported"],"backgroundTag":null,"analyzedSha":"c236dd0f930f831ec151e436e138ddc429a02a72","analyzedAt":"2026-08-13T20:27:11.027Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}