abpframework/abp · critical · AbpException
The distributed lock name '{configuration.LockName}' is used
Error message
The distributed lock name '{configuration.LockName}' is used by more than one background job worker (the default worker uses '{WorkerOptions.DistributedLockName}'). Each worker must have a unique lock name to run independently. What it means
Thrown during BackgroundJobWorkerManager.StartAsync when a dedicated worker's distributed lock name collides with another worker's lock name or with the default worker's lock name (AbpBackgroundJobWorkerOptions.DistributedLockName, default "AbpBackgroundJobWorker"). Each worker needs a unique lock to run independently; a duplicate would cause mutual exclusion to break or serialize the wrong workers. AddDedicatedWorker checks this eagerly, but StartAsync re-validates as a backstop.
Source
Thrown at framework/src/Volo.Abp.BackgroundJobs/Volo/Abp/BackgroundJobs/BackgroundJobWorkerManager.cs:79
foreach (var configuration in WorkerOptions.WorkerConfigurations)
{
var jobNames = configuration.JobArgsTypes
.Select(GetJobName)
.Distinct()
.ToList();
var alreadyConfigured = jobNames.Intersect(allDedicatedJobNames).ToList();
if (alreadyConfigured.Any())
{
throw new AbpException(
$"The following background job(s) are configured for more than one dedicated worker: {string.Join(", ", alreadyConfigured)}. " +
$"Each job type can be handled by only one dedicated worker.");
}
if (lockNames.Contains(configuration.LockName))
{
throw new AbpException(
$"The distributed lock name '{configuration.LockName}' is used by more than one background job worker " +
$"(the default worker uses '{WorkerOptions.DistributedLockName}'). Each worker must have a unique lock name to run independently.");
}
lockNames.Add(configuration.LockName);
allDedicatedJobNames.AddRange(jobNames);
dedicatedWorkers.Add(new DedicatedWorkerDefinition(configuration.LockName, jobNames));
}
foreach (var dedicatedWorker in dedicatedWorkers)
{
await StartWorkerAsync(dedicatedWorker.LockName, BackgroundJobNameFilter.Include(dedicatedWorker.JobNames), cancellationToken);
}
// Default worker processes every job that is not handled by a dedicated worker.
await StartWorkerAsync(null, BackgroundJobNameFilter.Exclude(allDedicatedJobNames), cancellationToken);
}
View on GitHub (pinned to 7ed43b1931)
Solutions
- Give each dedicated worker a unique lock name that does not match DistributedLockName (e.g. "AbpBackgroundJobEmailWorker").
- Use the parameterless AddDedicatedWorker<TArgs>() overload, which auto-generates a unique lock name from an MD5 hash of the job type names.
- If you customized DistributedLockName, ensure no dedicated worker uses the same string.
Example fix
// before — collides with the default lock name
Configure<AbpBackgroundJobWorkerOptions>(opts =>
{
opts.DistributedLockName = "MyJobWorker";
opts.AddDedicatedWorker<MyJobArgs>("MyJobWorker"); // collision
});
// after — distinct lock name
Configure<AbpBackgroundJobWorkerOptions>(opts =>
{
opts.DistributedLockName = "MyDefaultJobWorker";
opts.AddDedicatedWorker<MyJobArgs>("MyJobDedicatedWorker");
}); Defensive patterns
Strategy: validation
Validate before calling
string lockName = "MyDedicatedWorker";
var workerOpts = serviceProvider.GetRequiredService<IOptions<AbpBackgroundJobWorkerOptions>>().Value;
if (lockName == workerOpts.DistributedLockName ||
workerOpts.WorkerConfigurations.Any(c => c.LockName == lockName))
{
throw new InvalidOperationException($"Lock name '{lockName}' is already in use.");
}
options.AddDedicatedWorker(lockName, jobArgsTypes); Try / catch
try { options.AddDedicatedWorker(lockName, jobArgsTypes); }
catch (AbpException ex) when (ex.Message.Contains("distributed lock name"))
{
logger.LogError(ex, "Distributed lock name collision for dedicated worker.");
throw;
} Prevention
- Use the parameterless AddDedicatedWorker<TArgs>() overload to get an auto-generated unique lock name.
- Never use the default lock name ("AbpBackgroundJobWorker") for a dedicated worker.
- Keep a central list of lock names if you assign them explicitly.
When it happens
Trigger: Calling AddDedicatedWorker with a lockName that equals AbpBackgroundJobWorkerOptions.DistributedLockName (the default worker's lock). Registering two workers with the same explicit lock name. Changing DistributedLockName at runtime after workers are already registered so it now collides with a dedicated worker's name.
Common situations: Explicitly passing "AbpBackgroundJobWorker" as the lock name for a dedicated worker, not realizing it is reserved for the default worker. Copy-pasting a dedicated worker registration line and forgetting to change the lock name. Customizing DistributedLockName globally so it collides with an existing dedicated worker lock.
Related errors
- The following background job(s) are configured for more than
- No background job is registered for the args type '{argsType
- The background job args type '{duplicateType.FullName}' is a
- The distributed lock name '{lockName}' is already used by an
- Background job execution is disabled. This method should not
AI-assisted analysis of abpframework/abp@7ed43b1931 (2026-08-13).
Data as JSON: /api/errors/a7cc26d063e7171f.
Report an issue: GitHub.