immich-app/immich · warning · BadRequestException

Invalid job name: ${name}

Error message

Invalid job name: ${name}

What it means

Thrown by QueueService.start in the default switch case. The name passed through does not match any of the explicitly handled QueueName values (VideoConversion, StorageTemplateMigration, LibraryScanQueueAll, BackupDatabase, Ocr, etc.). BadRequestException with the offending name interpolated -> HTTP 400.

Source

Thrown at server/src/services/queue.service.ts:249

      case QueueName.FacialRecognition: {
        return this.jobRepository.queue({ name: JobName.FacialRecognitionQueueAll, data: { force } });
      }

      case QueueName.Library: {
        return this.jobRepository.queue({ name: JobName.LibraryScanQueueAll, data: { force } });
      }

      case QueueName.BackupDatabase: {
        return this.jobRepository.queue({ name: JobName.DatabaseBackup, data: { force } });
      }

      case QueueName.Ocr: {
        return this.jobRepository.queue({ name: JobName.OcrQueueAll, data: { force } });
      }

      default: {
        throw new BadRequestException(`Invalid job name: ${name}`);
      }
    }
  }

  private isConcurrentQueue(name: QueueName): name is ConcurrentQueueName {
    return ![
      QueueName.FacialRecognition,
      QueueName.StorageTemplateMigration,
      QueueName.DuplicateDetection,
      QueueName.BackupDatabase,
    ].includes(name);
  }

  async handleNightlyJobs() {
    const config = await this.getConfig({ withCache: false });
    const jobs: JobItem[] = [];

    if (config.nightlyTasks.databaseCleanup) {

View on GitHub (pinned to 199723261c)

Solutions

  1. Only call start on queues that have an explicit job to enqueue (see the switch cases).
  2. Validate the name against the startable subset (concurrent queues + the named serial queues) before calling.
  3. If a new QueueName was added, extend the switch in QueueService.start to handle it.

Example fix

// before
default: {
  throw new BadRequestException(`Invalid job name: ${name}`);
}

// after (list the accepted values)
default: {
  throw new BadRequestException(
    `Invalid job name: ${name}. Startable queues: videoConversion, storageTemplateMigration, library, backupDatabase, ocr, ...`,
  );
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate against the startable set before calling start.
const STARTABLE = new Set([
  'videoConversion','storageTemplateMigration','library',
  'backupDatabase','ocr','thumbnailGeneration','metadataExtraction',
  'faceDetection','facialRecognition','smartSearch','duplicateDetection','sidecar',
]);
if (!STARTABLE.has(name)) {
  throw new Error(`Queue ${name} has no start handler`);
}

Type guard

const isStartableQueue = (name: string): boolean => STARTABLE.has(name);

Try / catch

try {
  await queueService.handleCommand(auth, name, dto);
} catch (e) {
  if (e instanceof BadRequestException && /Invalid job name/i.test(e.message)) {
    // surface the accepted list to the operator
  }
  throw e;
}

Prevention

When it happens

Trigger: POST start-queue with a QueueName value that exists in the enum but has no start handler (e.g. BackgroundTask, Migration, Search, Sidecar, Workflow, IntegrityCheck, Editor), or with a non-QueueName string that slipped past the schema.

Common situations: Client sends a queue name that is pausable/processable but not startable; enum extended without updating the switch; typo or case mismatch in the queue name.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/c03fdb9d2e44d703. Report an issue: GitHub.