HangfireIO/Hangfire · error · NotSupportedException
Current storage doesn't support specifying queues directly f
Error message
Current storage doesn't support specifying queues directly for a specific job. Please use the QueueAttribute instead.
What it means
NotSupportedException thrown by CoreBackgroundJobFactory.Create when a job specifies a Queue (context.Job.Queue != null) but the configured JobStorage does not advertise the JobQueueProperty feature (checked via context.Storage.HasFeature(JobStorageFeatures.JobQueueProperty)). Per-job queue targeting via the Job constructor's queue parameter or the queue argument of FromExpression requires storage that understands queue assignment per job; otherwise the [Queue] attribute (a job filter that sets the queue at the state level) is the supported path.
Source
Thrown at src/Hangfire.Core/Client/CoreBackgroundJobFactory.cs:63
public int RetryAttempts
{
get { lock (_syncRoot) { return _retryAttempts; } }
set { lock (_syncRoot) { _retryAttempts = value; } }
}
public Func<int, TimeSpan> RetryDelayFunc
{
get { lock (_syncRoot) { return _retryDelayFunc; } }
set { lock (_syncRoot) { _retryDelayFunc = value; } }
}
public BackgroundJob Create(CreateContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Job.Queue != null && !context.Storage.HasFeature(JobStorageFeatures.JobQueueProperty))
{
throw new NotSupportedException("Current storage doesn't support specifying queues directly for a specific job. Please use the QueueAttribute instead.");
}
var parameters = context.Parameters.ToDictionary(
static x => x.Key,
static x => SerializationHelper.Serialize(x.Value, SerializationOption.User));
var createdAt = DateTime.UtcNow;
var expireIn = TimeSpan.FromDays(30);
return CreateBackgroundJobTwoSteps(context, parameters, createdAt, expireIn);
}
private BackgroundJob CreateBackgroundJobTwoSteps(CreateContext context, Dictionary<string, string> parameters, DateTime createdAt, TimeSpan expireIn)
{
var attemptsLeft = Math.Max(RetryAttempts, 0);
// Retry may cause multiple background jobs to be created, especially when there's
// a timeout-related exception. But initialization attempt will be performed onlyView on GitHub (pinned to c236dd0f93)
Solutions
- Use the [Queue("critical")] attribute on the job method/class instead of the queue parameter — it sets the queue through the EnqueuedState and is universally supported.
- Switch to a storage that supports per-job queues (e.g., SqlServer, Redis with a current package) which advertises JobQueueProperty.
- If you maintain a custom JobStorage, override HasFeature to return true for JobQueueProperty and implement queue-aware job creation.
Example fix
// before — requires JobQueueProperty support
BackgroundJob.Enqueue<MyService>(x => x.DoWork(), "critical");
// after — works with any storage
[Queue("critical")]
public class MyService { public void DoWork() { ... } }
// or on the method:
public class MyService {
[Queue("critical")]
public void DoWork() { ... }
} Defensive patterns
Strategy: validation
Validate before calling
var supportsPerJobQueue = JobStorage.Current.HasFeature(JobStorageFeatures.JobQueueProperty);
if (!supportsPerJobQueue && !string.IsNullOrEmpty(queueName))
throw new InvalidOperationException("Storage does not support per-job queues; use [Queue] attribute instead.");
// then enqueue normally or via attribute Type guard
public static bool StorageSupportsPerJobQueue(JobStorage storage)
=> storage != null && storage.HasFeature(JobStorageFeatures.JobQueueProperty); Try / catch
try { BackgroundJob.Enqueue<T>(x => x.DoWork(), "critical"); }
catch (NotSupportedException ex) when (ex.Message.Contains("queues directly"))
{ /* fall back to [Queue] attribute-based enqueue */ } Prevention
- Default to the [Queue("name")] attribute for queue routing — it works with all storages.
- Before using the per-job queue parameter, check JobStorage.Current.HasFeature(JobStorageFeatures.JobQueueProperty).
- Keep storage packages updated so feature support matches the Core version you target.
When it happens
Trigger: Calling Job.FromExpression(() => ..., queue: "critical") or new Job(type, method, args, "critical") against a storage (e.g., MemoryStorage in older versions, or a custom storage) that returns false for HasFeature(JobStorageFeatures.JobQueueProperty). Also triggered by BackgroundJob.Enqueue<T>(..., queue: ...) overloads when storage lacks the feature.
Common situations: Using MemoryStorage or a minimal storage implementation in development that does not implement per-job queue support; upgrading Hangfire and using the new per-job queue API against an older storage package; custom JobStorage implementations that do not declare JobQueueProperty.
Related errors
- value
- Current storage doesn't support specifying queues directly f
- Attempts value must be equal or greater than zero.
- DelaysInSeconds value must be an array of non-negative numbe
- client
AI-assisted analysis of HangfireIO/Hangfire@c236dd0f93 (2026-08-13).
Data as JSON: /api/errors/046bd1cd03cb6e9b.
Report an issue: GitHub.