{"record":{"id":"a3b91adb38cd1cd4","repo":"aaif-goose/goose","slug":"message-with-id-messageid-not-found-in-current","errorCode":null,"errorMessage":"Message with id ${messageId} not found in current messages","messagePattern":"Message with id (.+?) not found in current messages","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ui/desktop/src/acp/chatSessionController.ts","lineNumber":258,"sourceCode":"\nasync function updateMessage(\n  sessionId: string,\n  messageId: string,\n  newContent: string,\n  editType: 'fork' | 'edit',\n  retainedImages: ImageData[],\n  options: AcpSubmitMessageOptions\n): Promise<void> {\n  assertNoPendingPromptCancellation(sessionId);\n\n  const currentSnapshot = options.getCurrentSnapshot();\n  const storedSnapshot = acpChatSessionStore.getSnapshot(sessionId);\n  const activePromptAttemptId = storedSnapshot?.activePromptAttemptId;\n  const currentMessages = currentSnapshot?.messages ?? [];\n  const message = currentMessages.find((m) => m.id === messageId);\n\n  if (!message) {\n    throw new Error(`Message with id ${messageId} not found in current messages`);\n  }\n\n  if (editType === 'fork') {\n    await forkSessionWithEditedMessage(sessionId, message, newContent, retainedImages);\n    return;\n  }\n\n  const editSnapshot = currentSnapshot ?? storedSnapshot;\n  const isPendingToolPermission =\n    editSnapshot?.chatState === ChatState.WaitingForUserInput &&\n    getPendingToolConfirmationIds(editSnapshot?.messages ?? []).size > 0;\n  const isIdle = editSnapshot?.chatState === ChatState.Idle;\n  const pendingToolPermissionPromptAttemptId = isPendingToolPermission\n    ? activePromptAttemptId\n    : undefined;\n  const canEditInPlace = isIdle || pendingToolPermissionPromptAttemptId != null;\n\n  if (!canEditInPlace) {","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/ui/desktop/src/acp/chatSessionController.ts#L240-L276","documentation":"Thrown by the message-edit path in chatSessionController when the message id submitted for edit is not present in the current UI snapshot's messages array. The controller re-reads the live snapshot at submit time (options.getCurrentSnapshot()), so the id the caller captured earlier (e.g. from a rendered list) can be stale. It also falls back to nothing — there is no storedSnapshot lookup for the message itself.","triggerScenarios":"Submitting an edit for a message that was removed because the session was reset, cleared, or switched between render and submit; using a message id from a previous session id; a fork/branch operation replaced the message list; concurrent edit where another action already truncated the conversation.","commonSituations":"User opens the edit dialog, then the agent finishes and UI reconciles messages, then submits; message ids persisted in component state across a session switch; tests calling the edit API with fabricated ids.","solutions":["Pass the message id from the same snapshot you got it from, re-read immediately before calling submit.","Ensure the edit UI is disabled for messages that no longer exist (derive the editable list from the live snapshot).","Verify the sessionId matches the snapshot store entry — a mismatched session yields an empty currentMessages array.","Treat this error as a no-op UX signal (message gone) rather than a hard failure where appropriate."],"exampleFix":"// before\nconst message = currentMessages.find((m) => m.id === messageId);\nif (!message) {\n  throw new Error(`Message with id ${messageId} not found in current messages`);\n}\n\n// after (caller refreshes state and degrades gracefully)\nconst snapshot = options.getCurrentSnapshot();\nconst message = (snapshot?.messages ?? []).find((m) => m.id === messageId);\nif (!message) {\n  console.warn(`Message ${messageId} no longer present; ignoring edit`);\n  return; // or re-render from the fresh snapshot and re-prompt the user\n}","handlingStrategy":"validation","validationCode":"// Verify the message is still present in the live snapshot before submitting an edit\nfunction canEditMessage(snapshot: { messages: { id: string }[] } | undefined, messageId: string): boolean {\n  return Boolean(snapshot?.messages.some((m) => m.id === messageId));\n}\n\nif (!canEditMessage(options.getCurrentSnapshot(), messageId)) {\n  return; // message already gone; nothing to edit\n}","typeGuard":"function findEditableMessage(\n  messages: { id: string }[],\n  messageId: string\n): { id: string } | undefined {\n  return messages.find((m) => m.id === messageId);\n}","tryCatchPattern":"try {\n  await submitEditedMessage(sessionId, messageId, newContent, retainedImages, options);\n} catch (error) {\n  if (/not found in current messages/.test(String(error))) {\n    // Stale UI: refresh from the store and drop the edit silently\n    refreshFromSnapshot(sessionId);\n    return;\n  }\n  throw error;\n}","preventionTips":["Derive edit affordances from the same live snapshot used at submit time.","Invalidate cached message ids whenever the session id or snapshot identity changes.","Disable edit UI during session reset/clear transitions."],"tags":["race-condition","state","chat","acp","ui"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}