diff --git a/src/app/features/room-settings/ExportRoomHistory.tsx b/src/app/features/room-settings/ExportRoomHistory.tsx index 83596c6ee..da3a295c7 100644 --- a/src/app/features/room-settings/ExportRoomHistory.tsx +++ b/src/app/features/room-settings/ExportRoomHistory.tsx @@ -92,6 +92,16 @@ export function ExportRoomHistory({ requestClose }: ExportRoomHistoryProps) { const evId = ev.getId(); if (!evId || seen.has(evId)) continue; seen.add(evId); + // Advance the raw pagination boundary for EVERY event (any type, + // decrypted or not) — getTs() is unencrypted metadata. Gating this on + // a decrypted m.room.message let undecryptable/non-message old events + // stall oldestRawTs, so the fromTs break never fired → over-paginate + // and a false "truncated". + const ts = ev.getTs(); + // Require a positive ts: an event with a bogus 0/negative + // origin_server_ts must not collapse the boundary and trigger an early + // break (silent under-pagination in the export). + if (ts > 0 && ts < oldestRawTs) oldestRawTs = ts; // Attempt decryption for events that haven't been decrypted yet // (paginateEventTimeline may fetch events before the SDK decrypts them) if (ev.isEncrypted() && !ev.getClearContent()) { @@ -100,8 +110,6 @@ export function ExportRoomHistory({ requestClose }: ExportRoomHistoryProps) { } if (ev.getType() !== EventType.RoomMessage) continue; if (ev.isDecryptionFailure()) continue; - const ts = ev.getTs(); - if (ts < oldestRawTs) oldestRawTs = ts; if (fromTs !== null && ts < fromTs) continue; if (toTs !== null && ts > toTs) continue; const content = ev.getContent();