fix: repair corrupted group DMs, prevent ownerId nulling, show empty groups

Three fixes for group DM data integrity and display:

1. processOwnershipTransferEvent: use resolveOrCreateReplicatedUser instead
   of resolveLocalUser to guarantee a valid ownerId. The previous ?? null
   fallback converted group DMs into 1-on-1s when resolution failed.

2. Self-healing migration: detect group DMs with UUID-format federated_id
   but NULL owner_id (corrupted by the old fallback) and restore owner from
   the first remaining member. Found and repaired 7 across both instances.

3. Sidebar: group DMs with 0 other members (last person standing) now show
   as "Empty Group" instead of being hidden. 1-on-1 DMs with 0 others are
   still correctly filtered out.
This commit is contained in:
Jannis Braun
2026-03-27 17:38:09 +01:00
parent 44b6317c16
commit 41658ec2ef
4 changed files with 51 additions and 10 deletions
+12 -6
View File
@@ -1967,12 +1967,18 @@ function processOwnershipTransferEvent(
return;
}
// Resolve new owner to local user (for local ownerId)
const newOwnerLocal = resolveLocalUser(event.ownership.newOwner.homeUserId, db);
// Resolve new owner to local user — use resolveOrCreateReplicatedUser to
// guarantee we always get a valid user ID. Never fall back to null, as that
// would convert the group DM into a 1-on-1 and destroy its type identity.
const newOwnerLocal = resolveOrCreateReplicatedUser(
event.ownership.newOwner.homeUserId,
event.ownership.newOwner.homeInstance,
db,
);
db.update(schema.dmChannels)
.set({
ownerId: newOwnerLocal?.id ?? null,
ownerId: newOwnerLocal.id,
ownerHomeUserId: event.ownership.newOwner.homeUserId,
ownerHomeInstance: event.ownership.newOwner.homeInstance,
})
@@ -1982,7 +1988,7 @@ function processOwnershipTransferEvent(
connectionManager.sendToDmMembers(channel.id, {
type: 'dm_owner_updated',
dmChannelId: channel.id,
newOwnerId: newOwnerLocal?.id ?? event.ownership.newOwner.homeUserId,
newOwnerId: newOwnerLocal.id,
});
const prevOwnerLocal = event.ownership.previousOwner
@@ -1998,8 +2004,8 @@ function processOwnershipTransferEvent(
userId: prevOwnerId,
content: JSON.stringify({
event: 'owner_changed',
newOwnerId: newOwnerLocal?.id ?? event.ownership.newOwner.homeUserId,
newOwnerDisplayName: newOwnerLocal?.displayName ?? newOwnerBaseName,
newOwnerId: newOwnerLocal.id,
newOwnerDisplayName: newOwnerLocal.displayName ?? newOwnerBaseName,
}),
type: 'system',
createdAt: Date.now(),