{"record":{"id":"5a2fa845d0119d7d","repo":"immich-app/immich","slug":"cannot-add-another-owner","errorCode":null,"errorMessage":"Cannot add another owner","messagePattern":"Cannot add another owner","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/album.service.ts","lineNumber":294,"sourceCode":"\n      await this.eventRepository.emit('AlbumUpdate', {\n        id,\n        userIds: album.albumUsers.map(({ user }) => user.id),\n        recipientIds: [],\n      });\n    }\n\n    return results;\n  }\n\n  async addUsers(auth: AuthDto, id: string, { albumUsers }: AddUsersDto): Promise<AlbumResponseDto> {\n    await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [id] });\n\n    const album = await this.findOrFail(id, auth.user.id, { withAssets: false });\n\n    for (const { userId, role } of albumUsers) {\n      if (role === AlbumUserRole.Owner) {\n        throw new BadRequestException('Cannot add another owner');\n      }\n\n      const exists = album.albumUsers.some(({ user: { id } }) => id === userId);\n      if (exists) {\n        continue;\n      }\n\n      const user = await this.userRepository.get(userId, {});\n      if (!user) {\n        this.logger.debug('Adding user to album failed: user not found');\n        throw new BadRequestException('Invalid user');\n      }\n\n      await this.albumUserRepository.create({ userId, albumId: id, role });\n      await this.eventRepository.emit('AlbumInvite', { id, userId, senderName: auth.user.name });\n    }\n\n    return mapAlbum(await this.findOrFail(id, auth.user.id, { withAssets: true }));","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/album.service.ts#L276-L312","documentation":"Raised by AlbumService.addUsers when a requested albumUser entry has role AlbumUserRole.Owner. Albums are single-owner in Immich, so any attempt to add an additional owner (or re-assign ownership via the invite/share endpoint) is rejected with a 400 before the AlbumInvite event is emitted or any album user row is created. The offending input is the role field of an entry in the albumUsers array of AddUsersDto.","triggerScenarios":"PUT /albums/:id/users (or addUsers) with an entry like { userId, role: 'Owner' } in the albumUsers array.","commonSituations":"Clients echoing back the full member list (including the owner entry) from album info instead of sending only new members, or UIs that expose an owner role option.","solutions":["Send only 'Editor' or 'Viewer' roles in albumUsers","Filter out owner-role entries and the existing owner from the payload before calling addUsers","To transfer ownership, use the dedicated partner/ownership flow if available — there is no add-owner API"],"exampleFix":"// before\nawait api.addAlbumUsers(id, [{ userId, role: 'Owner' }]);\n// after\nawait api.addAlbumUsers(id, [{ userId, role: 'Editor' }]);","handlingStrategy":"validation","validationCode":"const safe = albumUsers.filter(u => u.role !== 'Owner');\nif (safe.length !== albumUsers.length) throw new Error('Owner role is not allowed for album members');","typeGuard":"function isAssignableRole(r: string): r is 'Editor' | 'Viewer' {\n  return r === 'Editor' || r === 'Viewer';\n}","tryCatchPattern":"try {\n  await api.addAlbumUsers(id, albumUsers);\n} catch (e) {\n  if ((e as Error).message === 'Cannot add another owner') {\n    return api.addAlbumUsers(id, albumUsers.filter(u => u.role !== 'Owner'));\n  }\n  throw e;\n}","preventionTips":["Only send Editor/Viewer roles to addUsers","Send only new members, not the full member list echoed back","Hide the Owner option in share UIs","Strip the existing owner entry from payloads built from album info"],"tags":["album","validation","permissions"],"backgroundTag":"invalid-enum-value","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"}