immich-app/immich · warning · NotFoundException

Not Found

Error message

Not Found

What it means

Thrown by PersonService.getThumbnail when personRepository.getById(id) returns null or the person has no thumbnailPath. NotFoundException with no message -> HTTP 404 with body 'Not Found'. Used after the permission check passes, so it indicates the thumbnail file is missing even though the person is accessible.

Source

Thrown at server/src/services/person.service.ts:166

    await this.jobRepository.queueAll(jobs);
  }

  async getById(auth: AuthDto, id: string): Promise<PersonResponseDto> {
    await this.requireAccess({ auth, permission: Permission.PersonRead, ids: [id] });
    return mapPerson(await this.findOrFail(id));
  }

  async getStatistics(auth: AuthDto, id: string): Promise<PersonStatisticsResponseDto> {
    await this.requireAccess({ auth, permission: Permission.PersonRead, ids: [id] });
    return this.personRepository.getStatistics(id);
  }

  async getThumbnail(auth: AuthDto, id: string): Promise<ImmichFileResponse> {
    await this.requireAccess({ auth, permission: Permission.PersonRead, ids: [id] });
    const person = await this.personRepository.getById(id);
    if (!person || !person.thumbnailPath) {
      throw new NotFoundException();
    }

    return new ImmichFileResponse({
      path: person.thumbnailPath,
      contentType: mimeTypes.lookup(person.thumbnailPath),
      cacheControl: CacheControl.PrivateWithoutCache,
    });
  }

  async create(auth: AuthDto, dto: PersonCreateDto): Promise<PersonResponseDto> {
    const person = await this.personRepository.create({
      ownerId: auth.user.id,
      name: dto.name,
      birthDate: dto.birthDate,
      isHidden: dto.isHidden,
      isFavorite: dto.isFavorite,
      color: dto.color,
    });

View on GitHub (pinned to 199723261c)

Solutions

  1. Re-run the thumbnail generation queue for faces (Administration > Jobs > Thumbnail Generation).
  2. Verify the storage volume is mounted and the thumbnail path on disk is readable.
  3. Provide a message to the NotFoundException so clients can distinguish 'no thumbnail' from 'no person'.

Example fix

// before
const person = await this.personRepository.getById(id);
if (!person || !person.thumbnailPath) {
  throw new NotFoundException();
}

// after
const person = await this.personRepository.getById(id);
if (!person) {
  throw new NotFoundException(`Person ${id} not found`);
}
if (!person.thumbnailPath) {
  throw new NotFoundException(`Person ${id} has no thumbnail`);
}
Defensive patterns

Strategy: validation

Validate before calling

// Before requesting the thumbnail, verify the person has one.
const person = await personService.getById(auth, id);
if (!person || !person.hasThumbnail) {
  // render a placeholder avatar instead of calling the thumbnail endpoint
  return PLACEHOLDER_AVATAR;
}

Type guard

const hasThumbnail = (p: PersonResponseDto | null | undefined): boolean =>
  !!p && (!!p.thumbnailPath || !!p.hasThumbnail);

Try / catch

try {
  return await personService.getThumbnail(auth, id);
} catch (e) {
  if (e instanceof NotFoundException) {
    // 404 from this endpoint means no thumbnail file; fall back to placeholder
    return PLACEHOLDER_AVATAR;
  }
  throw e;
}

Prevention

When it happens

Trigger: GET /people/{id}/thumbnail for a person whose thumbnail was never generated, was deleted from disk, or whose thumbnailPath column is empty.

Common situations: Thumbnail generation job failed or was interrupted; storage path was migrated/cleaned; the person was created manually (no face) and never had a thumbnail; cold migration left files behind.

Related errors


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