immich-app/immich · error · BadRequestException

Library not found

Error message

Library ${id} not found

What it means

getStatistics looks up aggregate statistics for a library via libraryRepository.getStatistics; when the repository returns no row the requested library id does not exist (or has no computable statistics), so the method converts the missing result into a 400 BadRequestException instead of returning an empty/undefined DTO. It is an existence guard on the id path parameter, not a data-format failure.

Solutions

  1. Verify the library id from the request actually exists (GET /libraries) before requesting statistics
  2. Handle the 400 response on the client by showing 'library not found' and refreshing the library list
  3. If the library was recently deleted, re-fetch collections to purge stale ids from the client state
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/library.service.ts:202 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/0589e18b6f887bd9. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/library.service.ts:202

      await this.unwatch(id);
    }
  }

  async watchAll() {
    if (!this.lock) {
      return false;
    }

    const libraries = await this.libraryRepository.getAll(false);
    for (const library of libraries) {
      await this.watch(library.id);
    }
  }

  async getStatistics(id: string): Promise<LibraryStatsResponseDto> {
    const statistics = await this.libraryRepository.getStatistics(id);
    if (!statistics) {
      throw new BadRequestException(`Library ${id} not found`);
    }
    return statistics;
  }

  async get(id: string): Promise<LibraryResponseDto> {
    const library = await this.findOrFail(id);
    return mapLibrary(library);
  }

  async getAll(): Promise<LibraryResponseDto[]> {
    const libraries = await this.libraryRepository.getAll(false);
    return libraries.map((library) => mapLibrary(library));
  }

  @OnJob({ name: JobName.LibraryDeleteCheck, queue: QueueName.Library })
  async handleQueueCleanup(): Promise<JobStatus> {
    this.logger.log('Checking for any libraries pending deletion...');
    const pendingDeletions = await this.libraryRepository.getAllDeleted();

View on GitHub (pinned to e55ac299a4)