Skip to content

Conversation

@abhinavkrin
Copy link
Member

@abhinavkrin abhinavkrin commented Nov 5, 2025

Proposed changes (including videos or screenshots)

This PR fixes a bug that causes "My Data → Export Data" jobs to remain stuck in the exporting state and never transition to completed.

Root cause:

  • A TypeError: Cannot read properties of null (reading 'userNameTable') is thrown from server/lib/dataExport/exportRoomMessagesToFile.ts when hideUserName/anonymization logic tries to access userNameTable while it is null.
  • The thrown error causes the export flow to halt and the job to remain stuck.

Issue(s)

Steps to test or reproduce

Further comments

SUP-909

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where user data export requests could remain stuck and never complete.
  • Tests

    • Expanded test coverage for data export functionality.

@abhinavkrin abhinavkrin requested a review from a team as a code owner November 5, 2025 14:13
@changeset-bot
Copy link

changeset-bot bot commented Nov 5, 2025

🦋 Changeset detected

Latest commit: 21b5b00

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 41 packages
Name Type
@rocket.chat/meteor Patch
@rocket.chat/core-typings Patch
@rocket.chat/rest-typings Patch
@rocket.chat/uikit-playground Patch
@rocket.chat/api-client Patch
@rocket.chat/apps Patch
@rocket.chat/core-services Patch
@rocket.chat/cron Patch
@rocket.chat/ddp-client Patch
@rocket.chat/freeswitch Patch
@rocket.chat/fuselage-ui-kit Patch
@rocket.chat/gazzodown Patch
@rocket.chat/http-router Patch
@rocket.chat/livechat Patch
@rocket.chat/model-typings Patch
@rocket.chat/ui-avatar Patch
@rocket.chat/ui-client Patch
@rocket.chat/ui-contexts Patch
@rocket.chat/web-ui-registration Patch
@rocket.chat/account-service Patch
@rocket.chat/authorization-service Patch
@rocket.chat/ddp-streamer Patch
@rocket.chat/omnichannel-transcript Patch
@rocket.chat/presence-service Patch
@rocket.chat/queue-worker Patch
@rocket.chat/stream-hub-service Patch
@rocket.chat/federation-matrix Patch
@rocket.chat/license Patch
@rocket.chat/media-calls Patch
@rocket.chat/omnichannel-services Patch
@rocket.chat/pdf-worker Patch
@rocket.chat/presence Patch
rocketchat-services Patch
@rocket.chat/models Patch
@rocket.chat/network-broker Patch
@rocket.chat/omni-core-ee Patch
@rocket.chat/mock-providers Patch
@rocket.chat/ui-video-conf Patch
@rocket.chat/ui-voip Patch
@rocket.chat/instance-status Patch
@rocket.chat/omni-core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 5, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@abhinavkrin abhinavkrin force-pushed the fix/export-user-data-stuck-null-username-table branch from 1e0c216 to a5ebda4 Compare November 5, 2025 14:15
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

Fixes data export requests that could remain stuck by refactoring the userNameTable structure from a nested object to a flat map, ensuring proper initialization throughout the export pipeline. Adds comprehensive test coverage for data download processing and includes a release note documenting the patch.

Changes

Cohort / File(s) Change Summary
Release documentation
.changeset/funny-rocks-admire.md
Adds patch release note for @rocket.chat/meteor documenting fix for stuck user data export requests.
Test infrastructure
apps/meteor/.mocharc.js
Registers new Mocha spec pattern for data export test suite (server/lib/dataExport/**/*.spec.ts).
Data export core logic
apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
Refactors usersMap from nested userNameTable structure to flat Record<string, string> keyed map. Updates function signatures to use IExportOperation['userNameTable'] type, simplifying parameter passing and all internal references.
Data export initialization
apps/meteor/server/methods/requestDataDownload.ts
Initializes userNameTable: {} on export operation object creation to prevent undefined access downstream.
Data export processing
apps/meteor/server/lib/dataExport/processDataDownloads.ts
Adds guard to initialize exportOperation.userNameTable to empty object during exporting phase.
Comprehensive test suite
apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
Introduces end-to-end test coverage for data download request and processing flow, mocking database models, file operations, and validating complete export lifecycle from initiation through file generation.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant requestDataDownload
    participant processDataDownloads
    participant exportRoomMessagesToFile
    participant FileSystem

    User->>requestDataDownload: Request data export
    requestDataDownload->>requestDataDownload: Create exportOperation<br/>with userNameTable: {}
    requestDataDownload-->>User: Pending export created

    Note over processDataDownloads: Async processing begins
    processDataDownloads->>processDataDownloads: Guard: Initialize userNameTable<br/>if undefined
    processDataDownloads->>exportRoomMessagesToFile: Process room messages<br/>with usersMap (flat map)
    exportRoomMessagesToFile->>exportRoomMessagesToFile: Obfuscate usernames<br/>directly in usersMap[username]
    exportRoomMessagesToFile->>FileSystem: Write exported data
    FileSystem-->>exportRoomMessagesToFile: Files created
    exportRoomMessagesToFile-->>processDataDownloads: Export complete
    processDataDownloads->>processDataDownloads: Update status to completed
    processDataDownloads-->>User: Export ready for download
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • exportRoomMessagesToFile.ts: Review the refactoring from nested to flat map structure across all usages; verify type alignment with IExportOperation['userNameTable'] and ensure no edge cases in username obfuscation logic are missed.
  • processDataDownloads.spec.ts: High-density test file with extensive mocking and proxyquire usage; verify mock setup completeness, assertion accuracy, and end-to-end scenario coverage.
  • Cross-file consistency: Verify that initialization of userNameTable as empty object in both requestDataDownload.ts and processDataDownloads.ts prevents undefined access in exportRoomMessagesToFile.ts.

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • sampaiodiego
  • scuciatto
  • ggazzo

Poem

🐰 A tangled map once caused exports to freeze,
Now flattened structures work with ease!
With guards and types to guide the way,
User data flows—no more delay. ✨📤

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: preventing export jobs from getting stuck when userNameTable is null, which directly addresses the core bug described in PR objectives.
Linked Issues check ✅ Passed The PR directly addresses the bug in SUP-909 where export operations were stuck. Code changes initialize userNameTable to prevent null reference errors and update type signatures to support proper handling of the userNameTable field throughout the export flow.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the export stuck issue: test coverage additions, type signature updates, initialization guards, and documentation via changeset. No unrelated modifications detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/export-user-data-stuck-null-username-table

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts (1)

28-35: Force persisted userNameTable to null so the regression stays covered

Right now the userNameTable: null initializer gets overwritten by the spread because the real code now passes {}. That means the spec never drives the legacy-null scenario and would still pass if the guard disappeared. Flip the assignment order (or explicitly set to null after the spread) so the stored operation actually has null before processDataDownloads runs.

-		create: async (data: any) => {
-			exportOperation = {
-				userNameTable: null, // need to keep this null for testing purposes
-				...data,
-				_id: 'exportOp1',
-				createdAt: new Date(),
-			};
+		create: async (data: any) => {
+			exportOperation = {
+				...data,
+				_id: 'exportOp1',
+				createdAt: new Date(),
+			};
+			exportOperation.userNameTable = null; // simulate legacy persisted null
apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1)

187-196: Default empty object prevents null pointer errors.

The default value usersMap: IExportOperation['userNameTable'] = {} is a critical part of the fix, ensuring that even if callers don't provide this parameter, the function won't encounter null/undefined errors.

Consider typing the userData parameter.

The any type on line 192 reduces type safety. If this is pre-existing and out of scope for this PR, it could be addressed in a future refactor.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 194f371 and a5ebda4.

📒 Files selected for processing (6)
  • .changeset/funny-rocks-admire.md (1 hunks)
  • apps/meteor/.mocharc.js (1 hunks)
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (4 hunks)
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts (1 hunks)
  • apps/meteor/server/lib/dataExport/processDataDownloads.ts (1 hunks)
  • apps/meteor/server/methods/requestDataDownload.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (15)
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx} : Write concise, technical TypeScript/JavaScript with accurate typing

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use descriptive test names that clearly communicate expected behavior

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx} : Avoid code comments in the implementation

Applied to files:

  • apps/meteor/.mocharc.js
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Maintain test isolation between test cases

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : All Playwright test files must be located under apps/meteor/tests/e2e/ and use the .spec.ts extension (e.g., login.spec.ts)

Applied to files:

  • apps/meteor/.mocharc.js
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use expect matchers (toEqual, toContain, toBeTruthy, toHaveLength, etc.) instead of assert statements

Applied to files:

  • apps/meteor/.mocharc.js
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure a clean state for each test execution

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (test, page, expect) consistently

Applied to files:

  • apps/meteor/.mocharc.js
  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,tsx,js,jsx} : Follow DRY by extracting reusable logic into helper functions or page objects

Applied to files:

  • apps/meteor/.mocharc.js
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: When generating tests, provide complete runnable TypeScript test files with proper imports, clear describe/test blocks, and adherence to these guidelines

Applied to files:

  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,tsx} : Implement proper wait strategies for dynamic content

Applied to files:

  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-09-16T22:08:51.490Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-09-16T22:08:51.490Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use test.step() to organize complex test scenarios

Applied to files:

  • apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
🧬 Code graph analysis (2)
apps/meteor/server/lib/dataExport/processDataDownloads.spec.ts (2)
apps/meteor/server/methods/requestDataDownload.ts (2)
  • requestDataDownload (25-109)
  • requestDataDownload (112-120)
apps/meteor/server/lib/dataExport/processDataDownloads.ts (1)
  • processDataDownloads (248-285)
apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (8)
apps/meteor/.mocharc.js (1)

16-16: Include data export specs in the mocha run

Good call adding this glob—without it the new server/lib/dataExport specs would stay invisible to the main mocha run.

.changeset/funny-rocks-admire.md (1)

1-5: Release note is spot on

Thanks for documenting this regression fix so downstream teams know the exporting stall is addressed.

apps/meteor/server/lib/dataExport/processDataDownloads.ts (1)

181-183: Guarding userNameTable prevents the observed TypeError

Initializing the map here keeps legacy operations (persisted with null) from crashing when exportRoomMessagesToFile reads from it.

apps/meteor/server/methods/requestDataDownload.ts (1)

87-87: Seed the username map on creation

Seeding the export operation with {} keeps new jobs from persisting null going forward—nice preventative hardening.

apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (4)

3-3: LGTM: Type import supports improved type safety.

Adding IExportOperation enables proper typing of the userNameTable parameter throughout the file, replacing less specific types.


11-21: LGTM: Flat map structure eliminates null pointer risk.

The refactoring from nested usersMap.userNameTable to flat usersMap directly addresses the root cause of the bug. The function correctly maintains username mappings through mutation, and Object.keys(usersMap).length + 1 works properly with the flat structure.


57-62: LGTM: Function signature aligns with the refactored structure.

The updated type IExportOperation['userNameTable'] provides better type safety than the previous nested structure and matches the changes in hideUserName.


231-251: LGTM: Consistent null-safe defaults throughout the export pipeline.

The default value usersMap: IExportOperation['userNameTable'] = {} on line 249 maintains consistency with exportRoomMessages and ensures the entire export flow is protected from null pointer errors.

@codecov
Copy link

codecov bot commented Nov 5, 2025

Codecov Report

❌ Patch coverage is 80.00000% with 16 lines in your changes missing coverage. Please review.
✅ Project coverage is 67.08%. Comparing base (2f6b016) to head (21b5b00).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37387      +/-   ##
===========================================
+ Coverage    67.01%   67.08%   +0.07%     
===========================================
  Files         3418     3419       +1     
  Lines       117751   117938     +187     
  Branches     21532    21581      +49     
===========================================
+ Hits         78907    79124     +217     
+ Misses       36164    36128      -36     
- Partials      2680     2686       +6     
Flag Coverage Δ
e2e 57.51% <ø> (+0.01%) ⬆️
unit 72.14% <80.00%> (+0.03%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dougfabris dougfabris added this to the 7.13.0 milestone Nov 5, 2025
@abhinavkrin abhinavkrin added the stat: QA assured Means it has been tested and approved by a company insider label Nov 5, 2025
@dionisio-bot dionisio-bot bot added the stat: ready to merge PR tested and approved waiting for merge label Nov 5, 2025
@kodiakhq kodiakhq bot merged commit bbc4eb8 into develop Nov 5, 2025
54 checks passed
@kodiakhq kodiakhq bot deleted the fix/export-user-data-stuck-null-username-table branch November 5, 2025 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants