immich-app/immich · warning · BadRequestException
Cannot leave a cluster group without any other members
Error message
Cannot leave a cluster group without any other members
What it means
Leaving a cluster group is only allowed when at least one other member remains. The service queries clusterGroupRepository.hasOtherMembers and throws this BadRequestException if the caller is the sole member, since removing the last member would orphan the group.
Solutions
- Add another member to the group before leaving.
- Delete/disband the group through the group management endpoint instead of leaving it.
- Verify group membership count first and show a different UI flow for single-member groups.
Example fix
// before await api.leaveClusterGroup(groupId); // sole member → error // after await api.addClusterGroupMember(groupId, otherUserId); // ensure another member exists await api.leaveClusterGroup(groupId);
Defensive patterns
Strategy: try-catch
Validate before calling
// Check remaining members before leaving
const members = await api.getClusterGroupMembers(groupId);
const others = members.filter(m => m.id !== currentUserId);
if (others.length === 0) {
// disband group instead of leaving
} Try / catch
try {
await api.leaveClusterGroup(groupId);
} catch (e) {
if (e.response?.data?.message === 'Cannot leave a cluster group without any other members') {
await api.deleteClusterGroup(groupId); // or add a member first
} else throw e;
} Prevention
- Check member count before offering the Leave action in UI.
- Promote/add a replacement member before the last admin-owner leaves.
- Offer explicit group deletion for single-member groups.
When it happens
Trigger: Calling the leave-cluster-group endpoint while your account is the only member of the group (hasOtherMembers returns false).
Common situations: A test/private cluster group created with just one user; other members removed earlier leaving you alone; trying to disband a group via the leave action instead of group deletion.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot remove stack's primary asset
- Cannot request to join your own cluster group
- Asset does not have valid dimensions
- Asset not found
- Asset not in stack
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/80f05695ac124a9f.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/cluster-group.service.ts:92
async regeneratePeople(auth: AuthDto, id: string) {
await this.requireAccess({ auth, permission: Permission.ClusterGroupRead, ids: [id] });
await this.jobRepository.queue({
name: JobName.FacialRecognitionQueueAll,
data: { clusterGroupId: id, force: true },
});
}
async leave(auth: AuthDto, clusterGroupId: string): Promise<void> {
await this.requireAccess({ auth, permission: Permission.ClusterGroupLeave, ids: [clusterGroupId] });
const hasOtherMembers = await this.clusterGroupRepository.hasOtherMembers({
clusterGroupId,
userId: auth.user.id,
});
if (!hasOtherMembers) {
throw new BadRequestException('Cannot leave a cluster group without any other members');
}
const clusterGroup = await this.clusterGroupRepository.create();
await this.personRepository.reassignCluster({ userId: auth.user.id, newClusterId: clusterGroup.id });
await this.userRepository.update(auth.user.id, { clusterGroupId: clusterGroup.id });
}
}
View on GitHub (pinned to e55ac299a4)