paperclipai/paperclip · error · QueuedCommentMutationError

queued_comment_not_pending

queued_comment_not_pending

Error message

The queued message is no longer pending

What it means

QueuedCommentMutationError with code queued_comment_not_pending, thrown from createEditQueuedComment when the commentId supplied to editQueuedComment cannot be found among the locked queue's pending entries. The queue was locked and the revision matched, but the target comment is no longer part of the pending queue.

Solutions

  1. Re-fetch the queue and confirm the commentId still appears in the pending entries before retrying
  2. Remove the edit affordance for comments no longer pending and refresh the queue view
  3. Verify the commentId and queueId belong to the same issue/queue
  4. If this recurs, check for multiple sessions mutating the same queue and serialize edits through one view

Example fix

// before
await editQueuedComment({ issue, actor, queueId, revision, commentId: staleId, body });

// after
const queue = await getQueuedComments({ issue, actor });
if (!queue.entries.some((e) => e.comment.id === commentId)) {
  throw new Error('comment no longer pending; refresh queue');
}
await editQueuedComment({ issue, actor, queueId, revision: queue.revision, commentId, body });
Defensive patterns

Strategy: validation

Validate before calling

const queue = await getQueuedComments({ issue, actor });
const entry = queue.entries.find((e) => e.comment.id === commentId);
if (!entry) throw new Error('comment is no longer pending; refresh the queue');

Type guard

function isPendingEntry(queue: { entries: { comment: { id: string } }[] }, commentId: string): boolean {
  return queue.entries.some((e) => e.comment.id === commentId);
}

Try / catch

try {
  await editQueuedComment(input);
} catch (e) {
  if (e?.code === 'queued_comment_not_pending') {
    await refreshQueue(); // entry gone: show current state
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Editing a commentId that was already dispatched, discarded, or removed between the client's snapshot and the locked queue read; passing a commentId belonging to a different queue or issue; a typo'd or deleted comment id.

Common situations: Stale UI listing a message that was discarded in another tab; client retrying an edit after the message was flushed by the wake scheduler; mixing up comment ids across queue revisions.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/eeac6764a108e06d. Report an issue: GitHub.

Appendix: source

Thrown at server/src/modules/wake-queue/application/queued-comment-use-cases.ts:91

  revision: string;
  body: string;
  now: Date;
};

export type EditQueuedCommentResult = {
  queue: QueuedCommentQueueSnapshot;
  activityPublication: QueuedCommentActivityPublication;
};

export function createEditQueuedComment(deps: { issueLock: QueuedCommentIssueLockWriter }) {
  return async function editQueuedComment(input: EditQueuedCommentInput): Promise<EditQueuedCommentResult> {
    return deps.issueLock.withLockedQueue(
      { issue: input.issue, actor: input.actor, queueId: input.queueId },
      async (locked, tx) => {
        requireMutationTarget(locked.queue, input.queueId, input.revision);
        const entry = locked.queue.entries.find((candidate) => candidate.comment.id === input.commentId);
        if (!entry) {
          throw new QueuedCommentMutationError("queued_comment_not_pending", "The queued message is no longer pending");
        }
        if (!entry.canEdit) {
          throw new QueuedCommentMutationForbiddenError("Only the queued message author can edit it");
        }

        const updated = await tx.updateCommentBody({
          issueId: input.issue.id,
          commentId: input.commentId,
          body: input.body,
          updatedAt: input.now,
        });
        if (!updated) {
          throw new QueuedCommentMutationError("queued_comment_not_pending", "The queued message is no longer pending");
        }
        await tx.touchIssueUpdatedAt({ issueId: input.issue.id, updatedAt: input.now });
        await tx.syncCommentReferences(input.commentId);
        await tx.syncCommentExternalObjectsSafely(input.commentId);

View on GitHub (pinned to 3f1d897a7c)