Bug Report: Delayed digest master unfindable after subscriber delete/re-create (subscriberId vs _subscriberId index mismatch)
Description
Unique partial index Guard from having two master jobs for same digest key, digest value, workflow and subscriber in libs/dal/src/repositories/job/job.schema.ts:429 keys on subscriberId (external string), while getExistingDelayedJobWithTheSameDigestValue in libs/dal/src/repositories/job/job.repository.ts:431 and every other digest query filter by _subscriberId (internal ObjectId).
If a subscriber is deleted and re-created with the same external ID, the lookup misses the old delayed master (wrong ObjectId), tries to insert a new one, and the unique index rejects it (same string). The subscriber is permanently stuck — can't find the existing master, can't create a new one. Subscriber deletion also doesn't clean up orphaned job records, so the blocker persists indefinitely.
Relevant code:
libs/dal/src/repositories/job/job.schema.ts:429-450— index usessubscriberId: 1libs/dal/src/repositories/job/job.repository.ts:431-445—findOne({ ..., _subscriberId: ObjectId(job._subscriberId), ... })apps/worker/src/app/workflow/usecases/add-job/merge-or-create-digest.usecase.ts:162— caller, thenmarkJobAsDigestMasteron miss- All other digest indexes/queries use
_subscriberId(e.g.job.schema.ts:373-379,job.repository.ts:420,484)
Reproduction steps
- Create subscriber with external ID
ext-123(internal_id=A). - Trigger a digest workflow with a
digestKey/digestValuefor that subscriber → delayed digest masterM1created with{ subscriberId: 'ext-123', _subscriberId: A, status: 'delayed', type: 'digest' }. - Delete the subscriber (orphan
M1remains — no cascade tojobs). - Re-create subscriber with same external ID
ext-123(new internal_id=B). - Trigger the same digest workflow for
ext-123again. - See error:
getExistingDelayedJobWithTheSameDigestValuequeries{ _subscriberId: B }→ missesM1(hasA) → attempts new master insert with{ subscriberId: 'ext-123', ... }→MongoServerError E11000 duplicate keyonGuard from having two master jobs....
Expected behavior
Repeat trigger either merges into the existing delayed master or creates a new master successfully — subscriber never gets permanently stuck after delete/re-create.
Actual Behavior with Screenshots
Lookup by _subscriberId=B returns null, insert with subscriberId='ext-123' hits the unique index from the orphan (_subscriberId=A) and throws duplicate key. Every subsequent trigger retries and fails the same way. No screenshot — backend error path.
Novu version
3.19.1 (apps/api/package.json), origin/next @ a3d9eeca70 (verified Sept 2026)
npm version
11.11.1
node version
v22.22.1
Provide any additional context for the Bug.
Suggested fix: change subscriberId: 1 → _subscriberId: 1 in the guard index at job.schema.ts:432 to match the query.
Deploy note (MongoDB index conflict): the index name stays the same but key spec changes, so existing DBs must db.jobs.dropIndex('Guard from having two master jobs for same digest key, digest value, workflow and subscriber') before the new index is created (otherwise IndexOptionsConflict/IndexKeySpecsConflict on startup with MONGO_AUTO_CREATE_INDEXES=true). Already-stuck subscribers also need the orphaned delayed digest job removed manually, e.g. db.jobs.deleteOne({ _id: ObjectId('...M1...') }) — the code fix alone does not unstick them.
Have you spent some time to check if this bug has been raised before?
- I checked and didn't find a similar issue (
gh search issues --repo novuhq/novu "Guard from having two master jobs"and"digest master subscriber"returned no matches)
Have you read the Contributing Guidelines?
- I have read the Contributing Guidelines
Are you willing to submit PR?
Yes I am willing to submit a PR!
Source: novuhq/novu