Hi Sowmya,
Thank you for the detailed responses — they actually help confirm the diagnosis.
We have now root-caused this under MOSIP-45189, and your records match the known issue exactly. This is a confirmed bug.
Root cause — race condition on a shared singleton
AnonymousProfileHelper is a Spring singleton (@Component) that holds per-request state (newUinData, oldUinData, regId, cbeff references, etc.) as mutable instance fields. Its buildAndsaveProfile() method is @Async, so it runs on a separate thread after the main request thread has returned.
When two registrations are processed close together, this sequence occurs:
- Request A sets
newUinData on the singleton and submits the async profile build.
- Request B arrives, detects a different
regId, and calls resetData() — which wipes A’s newUinData to null.
- A’s async thread then runs, reads
newUinData = null, and builds newProfile = null (while processName stays "New", since it is derived from oldUinData being null).
- The record is saved as
{"processName":"New","oldProfile":null,"newProfile":null}.
This is not an exception in the builder — it is silent state corruption from concurrent requests sharing one instance. It has been reproduced with a unit test that simulates this exact thread interleaving.
Why this is consistent with everything you observed
- No WARN/ERROR for the reg IDs — expected, since nothing throws; the profile is simply built from null state.
- Valid
uin_data exists and packets processed cleanly — also expected. The main flow persists the identity correctly; only the asynchronous anonymous-profile snapshot reads the stale/null state.
- No retry or reprocessing correlation — correct, this is a timing collision between concurrent requests, not a reprocessing artifact.
- Still seen at ~25k/day — the race can trigger whenever any two requests overlap on the singleton, so it is not limited to peak load. Higher volume simply makes it more frequent; lower volume makes it rarer, not impossible.
- No discernible pattern across reg IDs — expected, since occurrence depends purely on request timing, not on the data itself.
Impact
Please note these records are confined to the idrepo.anonymous_profile table, which by design holds anonymized snapshots for reporting/analytics purposes only (per the table’s own schema definition). It is written by ID Repository but never read back for identity resolution, authentication, or any functional flow. The affected individuals’ actual identity data in idrepo.uin is fully intact and unaffected — only the anonymized reporting snapshot for these registrations is incomplete.
Suggested workaround (until the fix is released)
Since the source identity data in idrepo.uin is intact, the affected reporting rows are recoverable. We suggest the following:
-
Identify the affected records:
SELECT id, cr_dtimes
FROM idrepo.anonymous_profile
WHERE profile IS NULL
OR (profile::jsonb ->> 'newProfile') IS NULL;
-
Backfill from idrepo.uin: the anonymous_profile.id is deterministically derived from the registration ID, and idrepo.uin retains the corresponding uin_data. A one-off remediation job can regenerate the anonymized profile for these rows from the existing uin_data, restoring the reporting snapshot without affecting the live flow.
As an interim measure to reduce the frequency of new occurrences, the anonymous-profile async executor pool can be tuned so the async build completes sooner relative to incoming requests. Please note this only narrows the timing window — it reduces, but does not eliminate, the occurrence. The complete resolution is the code fix tracked under MOSIP-45189.
Fix
The fix is being tracked under MOSIP-45189 and is targeted for an upcoming ID Repository release. We will update this thread once the release details are finalized.
Regards, Kamesh on behalf of Team MOSIP