From b506e8653b6a96d8bcd1aaf6fb985000a173c4a2 Mon Sep 17 00:00:00 2001 From: ngoiyaeric <1.15367894e+08+ngoiyaeric@users.noreply.github.com> Date: Thu, 9 Jul 2026 20:37:24 +0000 Subject: [PATCH] fix: deduplicate message IDs in saveChat to prevent ON CONFLICT error The AI state submit function uses a shared groupeId for multiple message types (response, resolution_search_result, related, followup), which all get the same ID. When onSetAIState calls saveChat, the batch insert hits: ERROR: ON CONFLICT DO UPDATE command cannot affect row a second time (21000) Fix: Before inserting, scan for duplicate IDs within the batch and append a unique suffix to any duplicates, ensuring every row in the INSERT has a distinct primary key. --- lib/actions/chat-db.ts | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/actions/chat-db.ts b/lib/actions/chat-db.ts index c4eea9ec..3fcdc2f9 100644 --- a/lib/actions/chat-db.ts +++ b/lib/actions/chat-db.ts @@ -112,13 +112,30 @@ export async function saveChat(chatData: NewChat, messagesData: Omit 0) { - const messagesToInsert = messagesData.map(msg => ({ - ...msg, - chatId: chatId!, // Ensure chatId is set for all messages - userId: msg.userId || chatData.userId!, // Ensure userId is set - })); + const seenIds = new Set(); + const messagesToInsert: typeof messages.$inferInsert[] = []; + + for (const msg of messagesData) { + let id = msg.id; + + // If we've already seen this ID in this batch, generate a unique one + while (seenIds.has(id)) { + id = `${id}-${Math.random().toString(36).substring(2, 8)}`; + } + seenIds.add(id); + + messagesToInsert.push({ + ...msg, + id, + chatId: chatId!, + userId: msg.userId || chatData.userId!, + }); + } + await tx.insert(messages).values(messagesToInsert).onConflictDoUpdate({ target: messages.id, set: { content: sql`EXCLUDED.content`, role: sql`EXCLUDED.role` } }); } return chatId;