diff --git a/lib/permissions/minimally-encoded-thread-permissions-validators.js b/lib/permissions/minimally-encoded-thread-permissions-validators.js
--- a/lib/permissions/minimally-encoded-thread-permissions-validators.js
+++ b/lib/permissions/minimally-encoded-thread-permissions-validators.js
@@ -5,7 +5,6 @@
 import {
   roleInfoValidator,
   threadCurrentUserInfoValidator,
-  memberInfoValidator,
 } from './minimally-encoded-raw-thread-info-validators.js';
 import { clientAvatarValidator } from '../types/avatar-types.js';
 import type {
@@ -14,11 +13,14 @@
 } from '../types/minimally-encoded-thread-permissions-types.js';
 import { threadTypeValidator } from '../types/thread-types-enum.js';
 import { threadEntityValidator } from '../utils/entity-text.js';
-import { tBool, tID, tShape } from '../utils/validation-utils.js';
+import { tBool, tID, tShape, tUserID } from '../utils/validation-utils.js';
 
 const relativeMemberInfoValidator: TInterface<RelativeMemberInfo> =
   tShape<RelativeMemberInfo>({
-    ...memberInfoValidator.meta.props,
+    id: tUserID,
+    role: t.maybe(tID),
+    minimallyEncoded: tBool(true),
+    isSender: t.Boolean,
     username: t.maybe(t.String),
     isViewer: t.Boolean,
   });
@@ -44,4 +46,4 @@
   pinnedCount: t.maybe(t.Number),
 });
 
-export { relativeMemberInfoValidator, threadInfoValidator };
+export { threadInfoValidator };
diff --git a/lib/selectors/user-selectors.js b/lib/selectors/user-selectors.js
--- a/lib/selectors/user-selectors.js
+++ b/lib/selectors/user-selectors.js
@@ -71,15 +71,16 @@
     const username = userInfos[memberInfo.id]
       ? userInfos[memberInfo.id].username
       : null;
+    const { permissions, ...memberInfoSansPermissions } = memberInfo;
     if (memberInfo.id === currentUserID) {
       relativeMemberInfos.unshift({
-        ...memberInfo,
+        ...memberInfoSansPermissions,
         username,
         isViewer: true,
       });
     } else {
       relativeMemberInfos.push({
-        ...memberInfo,
+        ...memberInfoSansPermissions,
         username,
         isViewer: false,
       });
diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -971,6 +971,10 @@
     | ServerMemberInfo,
 ): boolean {
   if (memberInfo.minimallyEncoded) {
+    invariant(
+      memberInfo.permissions,
+      'memberInfo must have permissions field in memberHasAdminPowers',
+    );
     return hasPermission(memberInfo.permissions, threadPermissions.CHANGE_ROLE);
   }
   return !!memberInfo.permissions[threadPermissions.CHANGE_ROLE]?.value;
diff --git a/lib/types/minimally-encoded-thread-permissions-types.js b/lib/types/minimally-encoded-thread-permissions-types.js
--- a/lib/types/minimally-encoded-thread-permissions-types.js
+++ b/lib/types/minimally-encoded-thread-permissions-types.js
@@ -131,11 +131,14 @@
   };
 };
 
-export type RelativeMemberInfo = $ReadOnly<{
-  ...MemberInfo,
+export type RelativeMemberInfo = {
+  +id: string,
+  +role: ?string,
+  +isSender: boolean,
+  +minimallyEncoded: true,
   +username: ?string,
   +isViewer: boolean,
-}>;
+};
 
 export type RawThreadInfo = $ReadOnly<{
   ...LegacyRawThreadInfo,