immich-app/immich · error · BadRequestException
Album not shared with user
Error message
Album not shared with user
What it means
Raised by AlbumService.removeUser when the target userId (after 'me' is resolved to auth.user.id) does not appear in album.albumUsers. The guard looks up the user in the album's shared-user list and fails if they were never invited or already removed, so the deletion of the album user row never happens. Indicates the client is trying to unshare from a user who has no membership in this album.
Solutions
- Re-fetch the album to confirm the user is still a member before removing
- Treat the 400 as already-removed and refresh local album state
- Remove a different, existing member ID (check for ID typos)
Example fix
// before
await api.removeAlbumUser(albumId, userId);
// after
const album = await api.getAlbumInfo(albumId);
if (album.albumUsers.some(u => u.userId === userId)) {
await api.removeAlbumUser(albumId, userId);
} Defensive patterns
Strategy: validation
Validate before calling
const album = await api.getAlbumInfo(albumId);
if (!album.albumUsers.some(m => m.userId === userId)) {
throw new Error(`User ${userId} is not a member of album ${albumId}`);
} Type guard
function isMember(userId: string, album: { albumUsers: { user: { id: string } }[] }): boolean {
return album.albumUsers.some(m => m.user.id === userId);
} Try / catch
try {
await api.removeAlbumUser(albumId, userId);
} catch (e) {
if ((e as Error).message === 'Album not shared with user') {
return; // already removed — idempotent no-op
}
throw e;
} Prevention
- Make removal idempotent: treat not-shared as success
- Refresh album state after any membership change
- Disable remove buttons for non-members in the UI
- Avoid double-submitting remove requests
When it happens
Trigger: DELETE /albums/:id/user/:userId where userId was never added to the album or was already removed (double-delete, stale UI state).
Common situations: Clicking remove twice, two admins removing the same member concurrently, or a client cache showing a member who already left/was removed.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Invalid user
- Admin setup is not available
- Cannot add another owner
- Cannot remove the last album owner
- Invalid album thumbnail
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/778d07369b62e64e.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/album.service.ts:324
}
await this.albumUserRepository.create({ userId, albumId: id, role });
await this.eventRepository.emit('AlbumInvite', { id, userId, senderName: auth.user.name });
}
return mapAlbum(await this.findOrFail(id, auth.user.id, { withAssets: true }));
}
async removeUser(auth: AuthDto, id: string, userId: string | 'me'): Promise<void> {
if (userId === 'me') {
userId = auth.user.id;
}
const album = await this.findOrFail(id, auth.user.id, { withAssets: false });
const exists = album.albumUsers.find(({ user: { id } }) => id === userId);
if (!exists) {
throw new BadRequestException('Album not shared with user');
}
if (
exists.role === AlbumUserRole.Owner &&
album.albumUsers.filter(({ role }) => role === AlbumUserRole.Owner).length === 1
) {
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> {View on GitHub (pinned to e55ac299a4)