immich-app/immich · error · BadRequestException

Invalid job name

Error message

Invalid job name

What it means

The manual job endpoint maps a ManualJobName enum value to a queue job via a switch (jobNameMap); the default case throws 400 BadRequestException 'Invalid job name' for anything that is not a known ManualJobName. This protects the queue from receiving an unknown job. Because the DTO already constrains the value to the enum, hitting this usually means the client sent a value not in the enum or the enum and client are out of sync.

Source

Thrown at server/src/services/job.service.ts:74

    case ManualJobName.IntegrityChecksumFilesRefresh: {
      return { name: JobName.IntegrityChecksumFiles, data: { refreshOnly: true } };
    }

    case ManualJobName.IntegrityMissingFilesDeleteAll: {
      return { name: JobName.IntegrityDeleteReportType, data: { type: IntegrityReport.MissingFile } };
    }

    case ManualJobName.IntegrityUntrackedFilesDeleteAll: {
      return { name: JobName.IntegrityDeleteReportType, data: { type: IntegrityReport.UntrackedFile } };
    }

    case ManualJobName.IntegrityChecksumFilesDeleteAll: {
      return { name: JobName.IntegrityDeleteReportType, data: { type: IntegrityReport.ChecksumFail } };
    }

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

@Injectable()
export class JobService extends BaseService {
  async create(dto: JobCreateDto): Promise<void> {
    await this.jobRepository.queue(asJobItem(dto));
  }

  @OnEvent({ name: 'JobRun' })
  async onJobRun(...[queueName, job]: ArgsOf<'JobRun'>) {
    try {
      await this.eventRepository.emit('JobStart', queueName, job);
      const response = await this.jobRepository.run(job);
      await this.eventRepository.emit('JobSuccess', { job, response });
      if (response && typeof response === 'string' && [JobStatus.Success, JobStatus.Skipped].includes(response)) {
        await this.onDone(job);

View on GitHub (pinned to 199723261c)

Solutions

  1. Send only values listed in the ManualJobName enum for the server version you run (check the openapi spec under open-api/).
  2. Regenerate the client SDK from the running server's /openapi.json so enum values match.
  3. If you believe the job should exist, upgrade both server and client to the same Immich release.
  4. Validate the job name client-side against the enum before posting.

Example fix

// before
api.jobs.run({ name: 'someOldJobName' });
// after (value from current ManualJobName enum)
api.jobs.run({ name: JobName.StorageMigration });
Defensive patterns

Strategy: validation

Validate before calling

import { ManualJobName } from '@immich/sdk'; // from generated client
const validNames = new Set(Object.values(ManualJobName));
if (!validNames.has(dto.name as ManualJobName)) {
  throw new Error(`Invalid job name: ${dto.name}`);
}
await api.jobApi.create(dto);

Type guard

const isManualJobName = (n: string): n is ManualJobName =>
  Object.values(ManualJobName).includes(n as ManualJobName);

Try / catch

try {
  await api.jobApi.create(dto);
} catch (e) {
  if (e.status === 400 && /Invalid job name/.test(e.message)) {
    // regenerate SDK from server openapi, or pick a valid enum value
  } else throw e;
}

Prevention

When it happens

Trigger: POST /jobs with a name that is not in ManualJobName (e.g. a typo, a value from a newer/older API version, or a raw string bypassing DTO validation).

Common situations: API client built against a different Immich version than the server; hand-crafted request with an invalid job name; enum renamed/removed between versions.

Related errors


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