diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js
--- a/web/chat/chat-input-bar.react.js
+++ b/web/chat/chat-input-bar.react.js
@@ -85,6 +85,7 @@
   +currentUserIsVoiced: boolean,
   +currentUserCanJoinThread: boolean,
   +threadFrozen: boolean,
+  +cancelPendingUpload: (uploadID: string) => void,
 };
 
 class ChatInputBar extends React.PureComponent<Props> {
@@ -240,7 +241,7 @@
       );
     }
 
-    const { pendingUploads, cancelPendingUpload } = this.props.inputState;
+    const { pendingUploads } = this.props.inputState;
     const multimediaPreviews = pendingUploads.map(pendingUpload => {
       const { uri, mediaType, thumbHash, dimensions } = pendingUpload;
       let mediaSource = { thumbHash, dimensions };
@@ -270,7 +271,7 @@
         <Multimedia
           mediaSource={mediaSource}
           pendingUpload={pendingUpload}
-          remove={cancelPendingUpload}
+          remove={this.props.cancelPendingUpload}
           multimediaCSSClass={css.multimedia}
           multimediaImageCSSClass={css.multimediaImage}
           key={pendingUpload.localID}
@@ -684,6 +685,14 @@
         [suggestedUsers, suggestedChats],
       );
 
+    const baseCancelPendingUpload = props.inputState.cancelPendingUpload;
+    const cancelPendingUpload = React.useCallback(
+      (uploadID: string) => {
+        baseCancelPendingUpload(props.threadInfo, uploadID);
+      },
+      [baseCancelPendingUpload, props.threadInfo],
+    );
+
     return (
       <ChatInputBar
         {...props}
@@ -701,6 +710,7 @@
         currentUserIsVoiced={currentUserIsVoiced}
         currentUserCanJoinThread={currentUserCanJoinThread}
         threadFrozen={threadFrozen}
+        cancelPendingUpload={cancelPendingUpload}
       />
     );
   });
diff --git a/web/input/input-state-container.react.js b/web/input/input-state-container.react.js
--- a/web/input/input-state-container.react.js
+++ b/web/input/input-state-container.react.js
@@ -43,10 +43,7 @@
 import { useNewThickThread } from 'lib/hooks/thread-hooks.js';
 import { useLegacyAshoatKeyserverCall } from 'lib/keyserver-conn/legacy-keyserver-call.js';
 import { getNextLocalUploadID } from 'lib/media/media-utils.js';
-import {
-  threadInfoSelector,
-  pendingToRealizedThreadIDsSelector,
-} from 'lib/selectors/thread-selectors.js';
+import { pendingToRealizedThreadIDsSelector } from 'lib/selectors/thread-selectors.js';
 import {
   dmOperationSpecificationTypes,
   type OutboundDMOperationSpecification,
@@ -145,7 +142,7 @@
 };
 type Props = {
   ...BaseProps,
-  +activeChatThreadInfo: ?ThreadInfo,
+  +activeChatThreadID: ?string,
   +drafts: { +[key: string]: string },
   +viewerID: ?string,
   +messageStoreMessages: { +[id: string]: RawMessageInfo },
@@ -616,21 +613,17 @@
     return threadCreationPromise;
   }
 
-  inputBaseStateSelector: (?ThreadInfo) => PropsAndState => BaseInputState =
-    _memoize((activeThreadInfo: ?ThreadInfo) =>
+  inputBaseStateSelector: (?string) => PropsAndState => BaseInputState =
+    _memoize(threadID =>
       createSelector(
         (propsAndState: PropsAndState) =>
-          activeThreadInfo
-            ? propsAndState.pendingUploads[activeThreadInfo.id]
-            : null,
+          threadID ? propsAndState.pendingUploads[threadID] : null,
         (propsAndState: PropsAndState) =>
-          activeThreadInfo
-            ? propsAndState.drafts[draftKeyFromThreadID(activeThreadInfo.id)]
+          threadID
+            ? propsAndState.drafts[draftKeyFromThreadID(threadID)]
             : null,
         (propsAndState: PropsAndState) =>
-          activeThreadInfo
-            ? propsAndState.textCursorPositions[activeThreadInfo.id]
-            : null,
+          threadID ? propsAndState.textCursorPositions[threadID] : null,
         (
           pendingUploads: ?{ [localUploadID: string]: PendingMultimediaUpload },
           draft: ?string,
@@ -655,7 +648,6 @@
               ];
             }
           }
-          const threadID = activeThreadInfo?.id;
           return ({
             pendingUploads: threadPendingUploads,
             assignedUploads,
@@ -665,8 +657,7 @@
               threadInfo: ThreadInfo,
               files: $ReadOnlyArray<File>,
             ) => this.appendFiles(threadInfo, files),
-            cancelPendingUpload: (localUploadID: string) =>
-              this.cancelPendingUpload(activeThreadInfo, localUploadID),
+            cancelPendingUpload: this.cancelPendingUpload,
             sendTextMessage: (
               messageInfo: RawTextMessageInfo,
               threadInfo: ThreadInfo,
@@ -1219,14 +1210,11 @@
     this.props.dispatch({ type: queueReportsActionType, payload: { reports } });
   }
 
-  cancelPendingUpload(threadInfo: ?ThreadInfo, localUploadID: string) {
-    invariant(threadInfo, 'threadID should be set in cancelPendingUpload');
-
+  cancelPendingUpload = (threadInfo: ThreadInfo, localUploadID: string) => {
     let revokeURL: ?string, abortRequest: ?() => void;
     this.setState(
       prevState => {
-        const threadID = threadInfo.id;
-        const newThreadID = this.getRealizedOrPendingThreadID(threadID);
+        const newThreadID = this.getRealizedOrPendingThreadID(threadInfo.id);
         const currentPendingUploads = prevState.pendingUploads[newThreadID];
         if (!currentPendingUploads) {
           return {};
@@ -1246,7 +1234,7 @@
           if (!threadTypeIsThick(threadInfo.type)) {
             void this.props.deleteUpload({
               id: serverID,
-              keyserverOrThreadID: threadID,
+              keyserverOrThreadID: threadInfo.id,
             });
           }
           if (isBlobServiceURI(pendingUpload.uri)) {
@@ -1294,7 +1282,7 @@
         }
       },
     );
-  }
+  };
 
   async processAndSendTextMessageDMOperation(
     messageInfo: RawTextMessageInfo,
@@ -1696,11 +1684,11 @@
   };
 
   render(): React.Node {
-    const { activeChatThreadInfo } = this.props;
+    const { activeChatThreadID } = this.props;
 
     // we're going with two selectors as we want to avoid
     // recreation of chat state setter functions on typeahead state updates
-    const inputBaseState = this.inputBaseStateSelector(activeChatThreadInfo)({
+    const inputBaseState = this.inputBaseStateSelector(activeChatThreadID)({
       ...this.state,
       ...this.props,
     });
@@ -1728,9 +1716,6 @@
     const activeChatThreadID = useSelector(
       state => state.navInfo.activeChatThreadID,
     );
-    const activeChatThreadInfo = useSelector(state =>
-      activeChatThreadID ? threadInfoSelector(state)[activeChatThreadID] : null,
-    );
     const drafts = useSelector(state => state.draftStore.drafts);
     const viewerID = useSelector(
       state => state.currentUserInfo && state.currentUserInfo.id,
@@ -1775,7 +1760,7 @@
     return (
       <InputStateContainer
         {...props}
-        activeChatThreadInfo={activeChatThreadInfo}
+        activeChatThreadID={activeChatThreadID}
         drafts={drafts}
         viewerID={viewerID}
         messageStoreMessages={messageStoreMessages}
diff --git a/web/input/input-state.js b/web/input/input-state.js
--- a/web/input/input-state.js
+++ b/web/input/input-state.js
@@ -66,7 +66,7 @@
     threadInfo: ThreadInfo,
     files: $ReadOnlyArray<File>,
   ) => Promise<boolean>,
-  +cancelPendingUpload: (localUploadID: string) => void,
+  +cancelPendingUpload: (threadInfo: ThreadInfo, localUploadID: string) => void,
   +sendTextMessage: (
     messageInfo: RawTextMessageInfo,
     threadInfo: ThreadInfo,