immich-app/immich · error · BadRequestException
User is owner
Error message
User is owner
What it means
Raised by AlbumService.updateUser when attempting to change the role of the album's owner. The endpoint for editing a member's role rejects updates targeting the owner because ownership cannot be changed this way (an album has exactly one owner); the target user must be a non-owner shared member to have their role edited.
Solutions
- Skip the owner when bulk-updating member roles
- Only call updateUser for members with Editor/Viewer roles
- Filter the member list client-side: update only entries whose user id differs from album.ownerId
Example fix
// before
for (const m of album.albumUsers) await api.updateAlbumUser(id, m.userId, { role: 'Viewer' });
// after
for (const m of album.albumUsers.filter(m => m.userId !== album.ownerId)) {
await api.updateAlbumUser(id, m.userId, { role: 'Viewer' });
} Defensive patterns
Strategy: validation
Validate before calling
const album = await api.getAlbumInfo(albumId);
if (album.ownerId === userId) throw new Error('Cannot change the owner role'); Type guard
function isNonOwnerMember(userId: string, album: { ownerId: string }): boolean {
return userId !== album.ownerId;
} Try / catch
try {
await api.updateAlbumUser(albumId, userId, { role });
} catch (e) {
if ((e as Error).message === 'User is owner') {
return; // skip owner in bulk role updates
}
throw e;
} Prevention
- Exclude the owner from bulk role-update loops
- Render the owner row as read-only in UIs
- Only update members whose current role is Editor/Viewer
- Compare against album.ownerId before every role change
When it happens
Trigger: PUT /albums/:id/user/:userId with the owner's userId in the path, regardless of the role in the DTO.
Common situations: Clients iterating all album members (including the owner) and updating each, or UIs rendering the owner as an editable row.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot add another owner
- Cannot remove the last album owner
- Album not shared with user
- Failed to create
- Failed to read: " ( )
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/0ca398bd72a2cc2e.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/album.service.ts:349
throw new BadRequestException('Cannot remove the last album owner');
}
// non-admin can remove themselves
if (auth.user.id !== userId) {
await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [id] });
}
await this.albumUserRepository.delete({ albumId: id, userId });
}
async updateUser(auth: AuthDto, id: string, userId: string, dto: UpdateAlbumUserDto): Promise<void> {
await this.requireAccess({ auth, permission: Permission.AlbumShare, ids: [id] });
const album = await this.findOrFail(id, userId, { withAssets: false });
const owner = album.albumUsers[0];
if (owner.user.id === userId) {
throw new BadRequestException('User is owner');
}
await this.albumUserRepository.update({ albumId: id, userId }, { role: dto.role });
}
private findOrFail(id: string, authUserId: string, options: AlbumInfoOptions) {
return findOrFail(() => this.albumRepository.getById(id, options, authUserId), 'Album');
}
}
View on GitHub (pinned to e55ac299a4)