Skip to content

Commit a863c99

Browse files
waleedlatif1claude
andcommitted
fix(copilot): make user-message persistence idempotent on message_id
persistUserMessage appended to copilot_chats.messages unconditionally (messages || [userMsg]::jsonb) with no check that the id already exists. A repeated POST for the same userMessageId — network retry, double submit, React double-effect, or a bypassed/expired send lock (Redis-down no-op) — therefore tacked on a duplicate array entry. The assistant append in terminal-state.ts is already guarded; this brings the user append to parity. (Evidence: 100% of duplicated message_ids in prod are role=user.) Guard the append with a containment check so it only concatenates when the array doesn't already hold a message with this id: CASE WHEN messages @> [{id}] THEN messages ELSE messages || [userMsg] END The client mints a fresh id per distinct send (verified across all hook revisions), so a repeated id is always the same message — skipping is safe and never drops a distinct message. conversationId/updatedAt stay unconditional so the stream marker still advances on a retry. The dual-write to copilot_messages is already idempotent (ON CONFLICT). Verified on Postgres: same id -> stays 1 element; different id -> 2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 75d9873 commit a863c99

1 file changed

Lines changed: 10 additions & 1 deletion

File tree

apps/sim/lib/copilot/chat/post.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,19 @@ async function persistUserMessage(params: {
326326
contexts,
327327
})
328328

329+
// Append the user message idempotently: only concatenate when the array
330+
// doesn't already contain a message with this id. A repeated id here is
331+
// always a retry/double-submit of the same message (the client mints a
332+
// fresh id per distinct send), so skipping the append avoids duplicate
333+
// entries while keeping the stream marker / updatedAt current.
329334
const [updated] = await db
330335
.update(copilotChats)
331336
.set({
332-
messages: sql`${copilotChats.messages} || ${JSON.stringify([userMsg])}::jsonb`,
337+
messages: sql`CASE
338+
WHEN ${copilotChats.messages} @> ${JSON.stringify([{ id: userMessageId }])}::jsonb
339+
THEN ${copilotChats.messages}
340+
ELSE ${copilotChats.messages} || ${JSON.stringify([userMsg])}::jsonb
341+
END`,
333342
conversationId: userMessageId,
334343
updatedAt: new Date(),
335344
})

0 commit comments

Comments
 (0)