immich-app/immich · error · BadRequestException

Invalid user

Error message

Invalid user

What it means

On album creation, any albumUsers entries other than the owner are checked against the user repository; if a listed userId does not exist, creation is aborted with 'Invalid user'. This prevents creating albums that reference dangling user IDs.

Solutions

  1. Remove the nonexistent userId from albumUsers and retry
  2. Refresh the shareable-user list from the API before creating the album
  3. Verify the userId is a valid UUID belonging to this instance
  4. Handle the 400 at the client and re-prompt the user to select share targets

Example fix

// before
const valid = await Promise.all(ids.map(id => userRepository.get(id, {})));
await api.createAlbum({ albumUsers: ids.map(id => ({ userId: id })) });
// after
const existing = (await api.listUsers()).users.map(u => u.id);
await api.createAlbum({ albumUsers: ids.filter(id => existing.includes(id)).map(id => ({ userId: id })) });
Defensive patterns

Strategy: validation

Validate before calling

const validIds = new Set((await api.listUsers()).map(u => u.id));
const albumUsers = requested.filter(u => validIds.has(u.userId));

Type guard

function userExists(id: string, known: Set<string>): boolean {
  return known.has(id);
}

Try / catch

try {
  await api.createAlbum(dto);
} catch (e) {
  if ((e as Error).message === 'Invalid user') {
    await refreshUserCache();
    return retryWithoutInvalidUsers(dto);
  }
  throw e;
}

Prevention

When it happens

Trigger: POST /albums with dto.albumUsers containing a userId that is not an existing user (typo, deleted user, or user from another instance).

Common situations: Stale client caches listing removed users, copy-pasted UUIDs from another environment, or concurrent user deletion between listing and album creation.

Understand the failure class

Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.

Related errors


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

Appendix: source

Thrown at server/src/services/album.service.ts:108

  async getMapMarkers(auth: AuthDto, id: string): Promise<MapMarkerResponseDto[]> {
    await this.requireAccess({ auth, permission: Permission.AlbumRead, ids: [id] });

    if (auth.sharedLink && !auth.sharedLink.showExif) {
      return [];
    }

    return this.mapRepository.getAlbumMapMarkers(id);
  }

  async create(auth: AuthDto, dto: CreateAlbumDto): Promise<AlbumResponseDto> {
    const albumUsers = (dto.albumUsers || []).filter(({ userId }) => userId !== auth.user.id);

    for (const { userId } of albumUsers) {
      const exists = await this.userRepository.get(userId, {});
      if (!exists) {
        this.logger.debug('Album creation failed: user not found');
        throw new BadRequestException('Invalid user');
      }
    }

    const allowedAssetIdsSet = await this.checkAccess({
      auth,
      permission: Permission.AssetShare,
      ids: dto.assetIds || [],
    });
    const assetIds = [...allowedAssetIdsSet].map((id) => id);

    const userMetadata = await this.userRepository.getMetadata(auth.user.id);

    const album = await this.albumRepository.create(
      {
        albumName: dto.albumName,
        description: dto.description,
        albumThumbnailAssetId: assetIds[0] || null,
        order: getPreferences(userMetadata).albums.defaultAssetOrder,

View on GitHub (pinned to e55ac299a4)