diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx
index 67c1acc4b16f..7a263fb9207c 100644
--- a/src/components/Search/SearchAutocompleteList.tsx
+++ b/src/components/Search/SearchAutocompleteList.tsx
@@ -503,15 +503,19 @@ function SearchAutocompleteList({
             const localRows: AutocompleteListItem[] = [];
             const serverRows: AutocompleteListItem[] = [];
             for (const item of nextStyledRecentReports) {
-                if (item.keyForList && frozenLocalRank.has(item.keyForList)) {
+                // Optimistic (invite) accounts are generated locally and are never server search results,
+                // so always keep them in the local section. Otherwise they briefly land in "Search results"
+                // before the frozen rank snapshot catches up, flashing across sections.
+                if (item.isOptimisticAccount || (item.keyForList && frozenLocalRank.has(item.keyForList))) {
                     localRows.push(item);
                 } else {
                     serverRows.push(item);
                 }
             }
             // Sort the local section by the rank captured at query-change time so it cannot
-            // reorder when the API returns.
-            localRows.sort((a, b) => (frozenLocalRank.get(a.keyForList ?? '') ?? 0) - (frozenLocalRank.get(b.keyForList ?? '') ?? 0));
+            // reorder when the API returns. Rows without a frozen rank (e.g. optimistic invite
+            // accounts) keep their original order at the end of the section.
+            localRows.sort((a, b) => (frozenLocalRank.get(a.keyForList ?? '') ?? Number.MAX_SAFE_INTEGER) - (frozenLocalRank.get(b.keyForList ?? '') ?? Number.MAX_SAFE_INTEGER));
 
             if (localRows.length > 0 || !isLoadingOptions) {
                 pushSection({title: translate('search.recentChats'), data: localRows, sectionIndex: sectionIndex++});
diff --git a/tests/unit/SearchAutocompleteListTest.tsx b/tests/unit/SearchAutocompleteListTest.tsx
index 16b77aa90ce3..d850466df63c 100644
--- a/tests/unit/SearchAutocompleteListTest.tsx
+++ b/tests/unit/SearchAutocompleteListTest.tsx
@@ -419,5 +419,65 @@ describe('SearchAutocompleteList', () => {
             // NewServer should appear after the local results (in the server section)
             expect(relevantOrder.indexOf('Charlie Report')).toBeLessThan(relevantOrder.indexOf('NewServer Report'));
         });
+
+        it('should keep an optimistic (invite) account in "Recent chats" instead of "Search results"', async () => {
+            const recentSearches: Record<string, {query: string; timestamp: string}> = {};
+            recentSearches['2024-01-01T00:00:00'] = {query: 'type:expense', timestamp: '2024-01-01T00:00:00'};
+
+            await waitForBatchedUpdates();
+            await Onyx.multiSet({
+                ...mockedReports,
+                [ONYXKEYS.PERSONAL_DETAILS_LIST]: mockedPersonalDetails,
+                [ONYXKEYS.BETAS]: mockedBetas,
+                [ONYXKEYS.RECENT_SEARCHES]: recentSearches,
+            });
+
+            render(<SearchRouterWrapper />);
+            await flushAllUpdates();
+
+            await waitFor(() => {
+                expect(screen.getByText('Recent chats')).toBeTruthy();
+            });
+
+            // Type a query that matches the existing reports so their local rank is frozen and non-empty
+            // (the invite account is not part of that snapshot).
+            const textInput = screen.getByTestId('search-autocomplete-text-input');
+            fireEvent.changeText(textInput, 'test');
+            await flushAllUpdates();
+
+            // Simulate an optimistic (invite) result arriving after the frozen rank was captured. It is not part
+            // of the frozen snapshot, so without special handling it would be treated as a server result and
+            // shown under "Search results". Because it is locally generated it must stay in "Recent chats".
+            getSearchOptionsSpy.mockReturnValue({
+                options: {
+                    recentReports: [
+                        {reportID: '103', keyForList: '103', text: 'Charlie Report', alternateText: 'charlie alt', lastMessageText: 'hey'},
+                        {reportID: '101', keyForList: '101', text: 'Alice Report', alternateText: 'alice alt', lastMessageText: 'hello'},
+                        {reportID: '102', keyForList: '102', text: 'Bob Report', alternateText: 'bob alt', lastMessageText: 'hi'},
+                        {reportID: '201', keyForList: '201', text: 'InviteAccount Report', alternateText: 'invite alt', lastMessageText: 'new', isOptimisticAccount: true},
+                    ],
+                    personalDetails: [],
+                    currentUserOption: null,
+                    userToInvite: null,
+                },
+            });
+            mockUseFilteredOptions.mockReturnValue({
+                options: {...mockedOptions},
+                isLoading: false,
+                loadMore: jest.fn(),
+                hasMore: false,
+                isLoadingMore: false,
+            });
+            await act(async () => {
+                await Onyx.set(ONYXKEYS.RAM_ONLY_IS_SEARCHING_FOR_REPORTS, false);
+            });
+            await flushAllUpdates();
+
+            // The optimistic account is locally generated, so it must never be treated as a server result.
+            await waitFor(() => {
+                expect(screen.getByText('InviteAccount Report')).toBeTruthy();
+            });
+            expect(screen.queryByText('Search results')).toBeNull();
+        });
     });
 });
