{"record":{"id":"5f99d458086bc6f1","repo":"immich-app/immich","slug":"failed-to-find-job-handler-for-job-jobkey-j","errorCode":null,"errorMessage":"Failed to find job handler for Job.${jobKey} (\"${jobName}\")","messagePattern":"Failed to find job handler for Job\\.(.+?) \\(\"(.+?)\"\\)","errorType":"exception","errorClass":"ImmichStartupError","httpStatus":null,"severity":"critical","filePath":"server/src/repositories/job.repository.ts","lineNumber":85,"sourceCode":"          label,\n          jobName,\n          queueName,\n          handler: handler.bind(instance),\n        };\n\n        this.logger.verbose(`Added job handler: ${jobName} => ${label}`);\n      }\n    }\n\n    // no missing handlers\n    for (const [jobKey, jobName] of Object.entries(JobName)) {\n      const item = this.handlers[jobName];\n      if (!item) {\n        const errorMessage = `Failed to find job handler for Job.${jobKey} (\"${jobName}\")`;\n        this.logger.error(\n          `${errorMessage}. Make sure to add the @OnJob({ name: JobName.${jobKey}, queue: QueueName.XYZ }) decorator for the new job.`,\n        );\n        throw new ImmichStartupError(errorMessage);\n      }\n    }\n  }\n\n  startWorkers() {\n    const { bull } = this.configRepository.getEnv();\n    for (const queueName of Object.values(QueueName)) {\n      this.logger.debug(`Starting worker for queue: ${queueName}`);\n      this.workers[queueName] = new Worker(\n        queueName,\n        (job) => this.eventRepository.emit('JobRun', queueName, job as JobItem),\n        { ...bull.config, concurrency: 1, name: ImmichWorker.Microservices },\n      );\n    }\n  }\n\n  watchWorkers() {\n    this.workerWatcher ??= setInterval(() => void this.checkWorkers(), WORKER_WATCH_INTERVAL_MS);","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/repositories/job.repository.ts#L67-L103","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a method decorated with @OnJob({ name: JobName.<key>, queue: QueueName.<q> }) on a registered service.","Ensure the service class is in a module that Nest discovers (registered in providers and picked up by setup).","Rebuild and restart."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// assert every JobName has a handler at build/test time\nimport { JobName } from '@immich/sdk';\nconst handlers = collectJobDecorators();\nconst missing = Object.values(JobName).filter((n) => !handlers.has(n));\nif (missing.length) throw new Error(`Missing handlers for: ${missing.join(', ')}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When adding a JobName enum value, add its handler in the same commit.","Keep a test that requires every JobName to map to a discovered handler.","Ensure handler-bearing services are registered in a discovered Nest module."],"tags":["jobs","bullmq","startup","nest","decorators","missing-handler"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}