{"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":"console","errorClass":"ImmichStartupError","httpStatus":null,"severity":"error","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/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/repositories/job.repository.ts#L67-L103","documentation":"After handler discovery, the job repository validates that every @OnJob-decorated item's job name has a registered handler. If an item references a JobName for which no handler exists (handlers are keyed by the resolved job name), setup throws an ImmichStartupError telling the developer to add the @OnJob decorator — this guards against jobs declared but never implemented.","triggerScenarios":"A @OnJob decorator uses a JobName whose handler registration was skipped or failed, or a job key was renamed/mistyped so the handlers map (keyed by string job name) has no entry for it — e.g. decorator name and enum value diverge after a refactor.","commonSituations":"Adding a new JobName enum value and a decorator but forgetting the handler method; renaming a JobName in one place only; a duplicated-handler error earlier preventing registration while the item still exists; typos in the decorator's name string.","solutions":["Add the missing handler method decorated with @OnJob({ name: JobName.<KEY>, queue: QueueName.XYZ }) as the error message suggests","Check for a JobName rename/mismatch: ensure the decorator name matches an enum value and the handler still exists after refactors","Resolve any earlier 'Failed to add job handler' duplicates so the handler registers correctly","Rebuild after changes (clean dist) to make sure the running code includes the new handler"],"exampleFix":"// before — job referenced but never handled\n@OnJob({ name: JobName.QueueSync, queue: QueueName.Backup })\n// no method anywhere handles JobName.QueueSync\n// after\nexport class BackupService {\n  @OnJob({ name: JobName.QueueSync, queue: QueueName.Backup })\n  async handleQueueSync(job: Job<QueueSyncParameters>) {\n    // ...\n  }\n}","handlingStrategy":"validation","validationCode":"const declared = new Set<string>(getAllJobNamesReferencedByDecorators());\nconst handled = new Set<string>(Object.keys(jobHandlers));\nconst missing = [...declared].filter((n) => !handled.has(n));\nif (missing.length > 0) throw new Error(`jobs without handlers: ${missing.join(', ')}`);","typeGuard":null,"tryCatchPattern":"try {\n  jobRepo.setup({ services });\n} catch (e) {\n  if (e instanceof ImmichStartupError && (e.message as string).startsWith('Failed to find job handler')) {\n    logger.fatal(`${e.message} — add the missing @OnJob handler before deploying.`);\n  }\n  throw e;\n}","preventionTips":["Pair every new JobName enum value with its handler in the same PR","Run a CI test enumerating JobName and asserting each has a decorator+handler","Rebuild dist after renames so stale compiled code doesn't reference old job names"],"tags":["startup","jobs","missing-handler","configuration"],"backgroundTag":"method-not-implemented","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}