diff --git a/web/src/features/groups/GroupAdminModal.tsx b/web/src/features/groups/GroupAdminModal.tsx
index 950f368c..53aab35a 100644
--- a/web/src/features/groups/GroupAdminModal.tsx
+++ b/web/src/features/groups/GroupAdminModal.tsx
@@ -410,6 +410,13 @@ function MutesSubView({ topicId, muted, onClose }: { topicId: string; muted: Gro
const queryClient = useQueryClient();
const [adding, setAdding] = useState(false);
const [error, setError] = useState('');
+ // `GroupMute` itself carries only a bare `user_id` (see its own type comment) -- resolve a real
+ // name/avatar the same way ConversationView.tsx's `memberByUserId` does, rather than rendering the
+ // raw id (this list previously crashed outright reading a `.user.display_name` that never existed
+ // on the real response, confirmed live: `Cannot read properties of undefined (reading 'user_id')`
+ // the moment a real muted member was ever rendered here).
+ const membersQuery = useQuery({ queryKey: ['group-members', topicId], queryFn: () => getAllGroupMembers(topicId) });
+ const memberByUserId = new Map((membersQuery.data || []).map((m) => [m.user_id, m]));
const invalidate = () => queryClient.invalidateQueries({ queryKey: ['group-mutes', topicId] });
const muteMutation = useMutation({
mutationFn: (userId: string) => muteGroupMembers(topicId, [{ user_id: userId, expires_at: null }]),
@@ -439,22 +446,25 @@ function MutesSubView({ topicId, muted, onClose }: { topicId: string; muted: Gro
/>
) : (
<>
- {muted.map((m) => (
-
-
- {avatarLetter(m.user.display_name)}
-
- {m.user.display_name || m.user.user_id}
-
-
- ))}
+ {muted.map((m) => {
+ const name = memberByUserId.get(m.user_id)?.display_name || m.user_id;
+ return (
+
+
+ {avatarLetter(name)}
+
+ {name}
+
+
+ );
+ })}