#12650·novu

Bug Report: Delayed digest master unfindable after subscriber delete/re-create (subscriberId vs _subscriberId index mismatch)

Author: ANSHSINGH050404Created Sep 14, 2026Updated Sep 14, 2026
Labelstriage

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 uses subscriberId: 1
  • libs/dal/src/repositories/job/job.repository.ts:431-445findOne({ ..., _subscriberId: ObjectId(job._subscriberId), ... })
  • apps/worker/src/app/workflow/usecases/add-job/merge-or-create-digest.usecase.ts:162 — caller, then markJobAsDigestMaster on miss
  • All other digest indexes/queries use _subscriberId (e.g. job.schema.ts:373-379, job.repository.ts:420,484)

Reproduction steps

  1. Create subscriber with external ID ext-123 (internal _id=A).
  2. Trigger a digest workflow with a digestKey/digestValue for that subscriber → delayed digest master M1 created with { subscriberId: 'ext-123', _subscriberId: A, status: 'delayed', type: 'digest' }.
  3. Delete the subscriber (orphan M1 remains — no cascade to jobs).
  4. Re-create subscriber with same external ID ext-123 (new internal _id=B).
  5. Trigger the same digest workflow for ext-123 again.
  6. See error: getExistingDelayedJobWithTheSameDigestValue queries { _subscriberId: B } → misses M1 (has A) → attempts new master insert with { subscriberId: 'ext-123', ... }MongoServerError E11000 duplicate key on Guard 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?

Are you willing to submit PR?

Yes I am willing to submit a PR!