abpframework/abp · error · AbpException
The background job args type '{duplicateType.FullName}' is a
Error message
The background job args type '{duplicateType.FullName}' is already assigned to a dedicated worker. Each job type can be handled by only one dedicated worker. What it means
Thrown by AbpBackgroundJobWorkerOptions.AddDedicatedWorker when one of the supplied jobArgsTypes is already part of an existing BackgroundJobWorkerConfiguration in WorkerConfigurations. The dedicated-worker model requires each job args type to be owned by exactly one worker, so a duplicate is rejected with the offending type's FullName.
Source
Thrown at framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/AbpBackgroundJobWorkerOptions.cs:137
CleanupDistributedLockName = "AbpBackgroundJobCleanup";
}
/// <summary>
/// Adds a dedicated worker that processes only the given job argument types.
/// </summary>
/// <param name="lockName">A unique distributed lock name for this worker.</param>
/// <param name="jobArgsTypes">The job argument types handled exclusively by this worker.</param>
public AbpBackgroundJobWorkerOptions AddDedicatedWorker(string lockName, params Type[] jobArgsTypes)
{
Check.NotNullOrEmpty(jobArgsTypes, nameof(jobArgsTypes));
var configuration = new BackgroundJobWorkerConfiguration(lockName, jobArgsTypes.Distinct().ToArray());
var duplicateType = configuration.JobArgsTypes.FirstOrDefault(
type => WorkerConfigurations.Any(c => c.JobArgsTypes.Contains(type)));
if (duplicateType != null)
{
throw new AbpException(
$"The background job args type '{duplicateType.FullName}' is already assigned to a dedicated worker. " +
$"Each job type can be handled by only one dedicated worker.");
}
if (lockName == DistributedLockName || WorkerConfigurations.Any(c => c.LockName == lockName))
{
throw new AbpException(
$"The distributed lock name '{lockName}' is already used by another background job worker. " +
$"Each worker must have a unique lock name.");
}
WorkerConfigurations.Add(configuration);
return this;
}
public AbpBackgroundJobWorkerOptions AddDedicatedWorker<TArgs>(string lockName)
{
return AddDedicatedWorker(lockName, typeof(TArgs));View on GitHub (pinned to 7ed43b1931)
Solutions
- Assign each job args type to only one dedicated worker; remove the duplicate registration.
- If two workers must handle related jobs, split them into distinct args types.
- Inspect all AddDedicatedWorker call sites and confirm each type appears in exactly one.
- Consolidate the overlapping types into a single worker configuration.
Example fix
// before
options.AddDedicatedWorker("worker-a", typeof(EmailJobArgs));
options.AddDedicatedWorker("worker-b", typeof(EmailJobArgs)); // throws duplicate
// after
options.AddDedicatedWorker("worker-a", typeof(EmailJobArgs));
options.AddDedicatedWorker("worker-b", typeof(SmsJobArgs)); Defensive patterns
Strategy: validation
Validate before calling
var existing = options.WorkerConfigurations.SelectMany(c => c.JobArgsTypes);
var duplicates = jobArgsTypes.Where(t => existing.Contains(t)).ToList();
if (duplicates.Any()) { /* don't call AddDedicatedWorker for these */ } Type guard
null
Try / catch
try { options.AddDedicatedWorker(lockName, types); }
catch (AbpException ex) when (ex.Message.Contains("already assigned to a dedicated worker"))
{ /* merge into existing worker or drop duplicate types */ } Prevention
- Register each job args type with exactly one worker.
- Centralize dedicated-worker registration to a single composition root.
- Use distinct args types per feature to avoid cross-collisions.
- Unit-test configuration startup to catch duplicates early.
When it happens
Trigger: Calling AddDedicatedWorker(lockName, typeof(SomeJobArgs)) (or the generic overloads) where SomeJobArgs was already passed to a previous AddDedicatedWorker call.
Common situations: Two modules/hosts each register a dedicated worker for the same job args type; refactoring split one worker into two but left overlapping types; copy-paste of AddDedicatedWorker calls; a shared job type reused across feature modules.
Related errors
- The distributed lock name '{lockName}' is already used by an
- Background job execution is disabled. This method should not
- Job names must be empty when the filter mode is None.
- Job names cannot be empty when the filter mode is Include or
- Job args types cannot contain null.
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/2ee3c972c9d894f7.
Report an issue: GitHub.