immich-app/immich · critical · ImmichStartupError

Failed to find job handler for Job.${jobKey} ("${jobName}")

Error message

Failed to find job handler for Job.${jobKey} ("${jobName}")

What it means

After discovery, JobRepository.setup iterates every JobName enum value and asserts a handler exists. If any JobName has no registered handler it logs the hint (add the @OnJob decorator) and throws ImmichStartupError('Failed to find job handler for Job.<key> ("<name>")'). Adding a new JobName without a handler is a startup-blocking bug.

Source

Thrown at server/src/repositories/job.repository.ts:85

          label,
          jobName,
          queueName,
          handler: handler.bind(instance),
        };

        this.logger.verbose(`Added job handler: ${jobName} => ${label}`);
      }
    }

    // no missing handlers
    for (const [jobKey, jobName] of Object.entries(JobName)) {
      const item = this.handlers[jobName];
      if (!item) {
        const errorMessage = `Failed to find job handler for Job.${jobKey} ("${jobName}")`;
        this.logger.error(
          `${errorMessage}. Make sure to add the @OnJob({ name: JobName.${jobKey}, queue: QueueName.XYZ }) decorator for the new job.`,
        );
        throw new ImmichStartupError(errorMessage);
      }
    }
  }

  startWorkers() {
    const { bull } = this.configRepository.getEnv();
    for (const queueName of Object.values(QueueName)) {
      this.logger.debug(`Starting worker for queue: ${queueName}`);
      this.workers[queueName] = new Worker(
        queueName,
        (job) => this.eventRepository.emit('JobRun', queueName, job as JobItem),
        { ...bull.config, concurrency: 1, name: ImmichWorker.Microservices },
      );
    }
  }

  watchWorkers() {
    this.workerWatcher ??= setInterval(() => void this.checkWorkers(), WORKER_WATCH_INTERVAL_MS);

View on GitHub (pinned to 199723261c)

Solutions

  1. Add a method decorated with @OnJob({ name: JobName.<key>, queue: QueueName.<q> }) on a registered service.
  2. Ensure the service class is in a module that Nest discovers (registered in providers and picked up by setup).
  3. Rebuild and restart.
Defensive patterns

Strategy: validation

Validate before calling

// assert every JobName has a handler at build/test time
import { JobName } from '@immich/sdk';
const handlers = collectJobDecorators();
const missing = Object.values(JobName).filter((n) => !handlers.has(n));
if (missing.length) throw new Error(`Missing handlers for: ${missing.join(', ')}`);

Prevention

When it happens

Trigger: A new entry was added to the JobName enum but no service method was decorated with @OnJob({ name: JobName.<that> }); or the handler-bearing service was not registered/discovered.

Common situations: Adding a job in a fork/feature branch and forgetting the handler; a service module not being imported so its handlers are never discovered; renaming a JobName without updating decorators.

Related errors


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