{"record":{"id":"3d45cf54fc4a1a17","repo":"paperclipai/paperclip","slug":"queued-comment-already-dispatching-the-message-is-being","errorCode":"queued_comment_already_dispatching","errorMessage":"The queued message is already being dispatched","messagePattern":"The queued message is already being dispatched","errorType":"error_code","errorClass":"QueuedCommentMutationError","httpStatus":null,"severity":"error","filePath":"server/src/modules/wake-queue/application/queued-comment-use-cases.ts","lineNumber":63,"sourceCode":"  }\n  if (queue.revision !== revision) {\n    throw new QueuedCommentMutationError(\"queued_comment_revision_conflict\", \"The queued messages changed in another session\");\n  }\n}\n\nasync function updateQueueRunCommentIdsGuarded(\n  tx: QueuedCommentQueueTransaction,\n  input: { queueRun: QueuedCommentRunRow | null; ids: string[]; updatedAt: Date },\n): Promise<QueuedCommentRunRow | null> {\n  if (!input.queueRun) return null;\n  const updated = await tx.updateQueueRunCommentIds({\n    queueRunId: input.queueRun.id,\n    contextSnapshot: input.queueRun.contextSnapshot,\n    ids: input.ids,\n    updatedAt: input.updatedAt,\n  });\n  if (!updated) {\n    throw new QueuedCommentMutationError(\"queued_comment_already_dispatching\", \"The queued message is already being dispatched\");\n  }\n  return updated;\n}\n\nexport type EditQueuedCommentInput = {\n  issue: QueuedCommentIssueContext;\n  actor: QueuedCommentActor;\n  commentId: string;\n  queueId: string;\n  revision: string;\n  body: string;\n  now: Date;\n};\n\nexport type EditQueuedCommentResult = {\n  queue: QueuedCommentQueueSnapshot;\n  activityPublication: QueuedCommentActivityPublication;\n};","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/modules/wake-queue/application/queued-comment-use-cases.ts#L45-L81","documentation":"QueuedCommentMutationError with code queued_comment_already_dispatching. Thrown by updateQueueRunCommentIdsGuarded when the guarded conditional update of the queue run's comment-ids row affects no rows (updated is falsy). The conditional update only matches while the run is still mutable; if the queueRun row was already taken by the dispatcher, the update matches nothing and the library concludes the queued message is being dispatched concurrently.","triggerScenarios":"Calling updatedQueueRun or createDiscardQueuedComment paths that touch the queue run when a dispatcher (wake/flush worker) has concurrently claimed or is draining the same queue run row between the read of queueRun and the guarded update.","commonSituations":"A user discards or edits a queued message at the exact moment the scheduled wake fires; a slow UI holding a stale queueRun snapshot while the dispatcher advances; concurrent workers racing on the same queue run row.","solutions":["Re-read the queue state; if the message is now dispatched, treat the mutation as no longer applicable and refresh the UI","Retry the mutation after a short delay only if the queue returns to a pending state","Do not retry blindly during an active dispatch window — surface 'message is being sent' to the user instead","Guard client-side by disabling edit/discard controls once a dispatch has been triggered"],"exampleFix":"// before\nawait discardQueuedComment({ issue, actor, queueId, revision, commentId }); // races with dispatch\n\n// after\ntry {\n  await discardQueuedComment({ issue, actor, queueId, revision, commentId });\n} catch (e) {\n  if (e.code === 'queued_comment_already_dispatching') {\n    // message is being sent: refresh state, do not retry now\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isDispatchSafe(run: { status: string } | null): boolean {\n  return run !== null && run.status === 'pending';\n}","tryCatchPattern":"try {\n  await discardQueuedComment(input);\n} catch (e) {\n  if (e?.code === 'queued_comment_already_dispatching') {\n    await refreshQueue(); // dispatch in progress; surface status, no retry now\n    return;\n  }\n  throw e;\n}","preventionTips":["Disable edit/discard controls once a dispatch is triggered","Re-read queue state before mutations after any dispatch activity","Avoid mutating during scheduled wake/flush windows","Retry only after confirming the queue returned to pending"],"tags":["concurrency","race-condition","dispatch","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}