immich-app/immich · warning · BadRequestException
The BackgroundTask queue cannot be paused
Error message
The BackgroundTask queue cannot be paused
What it means
Thrown by QueueService.update when dto.isPaused === true AND name === QueueName.BackgroundTask. The BackgroundTask queue runs essential housekeeping (cleanup, sidecar writes, etc.) and must never be paused, so the guard hard-rejects the request. BadRequestException -> HTTP 400.
Source
Thrown at server/src/services/queue.service.ts:158
}
async getAll(_auth: AuthDto): Promise<QueueResponseDto[]> {
return Promise.all(Object.values(QueueName).map((name) => this.getByName(name)));
}
async getAllLegacy(auth: AuthDto): Promise<QueuesResponseLegacyDto> {
const responses = await this.getAll(auth);
return mapQueuesLegacy(responses);
}
get(auth: AuthDto, name: QueueName): Promise<QueueResponseDto> {
return this.getByName(name);
}
async update(auth: AuthDto, name: QueueName, dto: QueueUpdateDto): Promise<QueueResponseDto> {
if (dto.isPaused === true) {
if (name === QueueName.BackgroundTask) {
throw new BadRequestException(`The BackgroundTask queue cannot be paused`);
}
await this.jobRepository.pause(name);
} else if (dto.isPaused === false) {
await this.jobRepository.resume(name);
}
return this.getByName(name);
}
searchJobs(auth: AuthDto, name: QueueName, dto: QueueJobSearchDto): Promise<QueueJobResponseDto[]> {
return this.jobRepository.searchJobs(name, dto);
}
async emptyQueue(auth: AuthDto, name: QueueName, dto: QueueDeleteDto) {
await this.jobRepository.empty(name);
if (dto.failed) {
await this.jobRepository.clear(name, QueueCleanType.Failed);
}View on GitHub (pinned to 199723261c)
Solutions
- Exclude QueueName.BackgroundTask from any pause-all logic.
- Filter the queue list client-side before issuing pause requests: skip 'backgroundTask'.
- If BackgroundTask is overloaded, scale workers instead of pausing the queue.
Example fix
// before
if (name === QueueName.BackgroundTask) {
throw new BadRequestException(`The BackgroundTask queue cannot be paused`);
}
// client-side guard
const pausable = queueNames.filter((n) => n !== QueueName.BackgroundTask);
await Promise.all(pausable.map((n) => api.put(`/admin/queues/${n}`, { isPaused: true }))); Defensive patterns
Strategy: validation
Validate before calling
// Never attempt to pause BackgroundTask.
const pausable = queueNames.filter((n) => n !== QueueName.BackgroundTask);
for (const name of pausable) {
await queueService.update(auth, name, { isPaused: true });
} Type guard
const isPausable = (name: QueueName): boolean => name !== QueueName.BackgroundTask;
Try / catch
try {
await queueService.update(auth, name, { isPaused: true });
} catch (e) {
if (e instanceof BadRequestException && /BackgroundTask/i.test(e.message)) {
// expected: skip this queue
return;
}
throw e;
} Prevention
- Hard-code an exclusion list for BackgroundTask in any pause-all automation.
- Filter the queue list in the admin UI before showing pause toggles.
- Document that BackgroundTask is intentionally unstoppable.
When it happens
Trigger: PUT /admin/queues/backgroundTask with body { isPaused: true }; a bulk 'pause all queues' client loop that includes BackgroundTask.
Common situations: Automation script iterating over all QueueName values to pause them; admin UI 'pause all' button without an exclusion list; misunderstanding that BackgroundTask is special.
Related errors
- Job is already running
- Invalid job name: ${name}
- Invalid job name
- User not found
- Unsupported file type ${filename}
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/16b6dbbb0ccb3ebc.
Report an issue: GitHub.