{"record":{"id":"9790557c565c319c","repo":"mastra-ai/mastra","slug":"notification-input-id-was-not-found-for-thread","errorCode":null,"errorMessage":"Notification ${input.id} was not found for thread ${input.threadId}","messagePattern":"Notification (.+?) was not found for thread (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/notifications/storage.ts","lineNumber":164,"sourceCode":"    const results = [...this.#notifications.values()]\n      .filter(record => record.status === 'pending')\n      .filter(record => !input.agentId || record.agentId === input.agentId)\n      .filter(record => !input.resourceId || record.resourceId === input.resourceId)\n      .filter(record => dueTime(record) <= now)\n      .sort((a, b) => dueTime(a) - dueTime(b) || a.updatedAt.getTime() - b.updatedAt.getTime());\n    return results.slice(0, input.limit ?? results.length).map(cloneRecord);\n  }\n\n  async getNotification(input: { threadId: string; id: string }): Promise<NotificationRecord | null> {\n    const record = this.#notifications.get(notificationKey(input.threadId, input.id));\n    if (!record) return null;\n    return cloneRecord(record);\n  }\n\n  async updateNotification(input: UpdateNotificationInput): Promise<NotificationRecord> {\n    const existing = this.#notifications.get(notificationKey(input.threadId, input.id));\n    if (!existing) {\n      throw new Error(`Notification ${input.id} was not found for thread ${input.threadId}`);\n    }\n    const now = new Date();\n    const next: NotificationRecord = {\n      ...existing,\n      ...(input.status ? { status: input.status, ...statusTimestamp(input.status, now) } : {}),\n      ...(input.summary !== undefined ? { summary: input.summary } : {}),\n      ...(input.payload !== undefined ? { payload: cloneValue(input.payload) } : {}),\n      ...(input.attributes !== undefined ? { attributes: cloneValue(input.attributes) } : {}),\n      ...(input.metadata !== undefined ? { metadata: cloneValue(input.metadata) } : {}),\n      ...(input.deliverAt !== undefined ? { deliverAt: input.deliverAt ?? undefined } : {}),\n      ...(input.summaryAt !== undefined ? { summaryAt: input.summaryAt ?? undefined } : {}),\n      ...(input.deliveryReason !== undefined ? { deliveryReason: input.deliveryReason } : {}),\n      ...(input.deliveryAttempts !== undefined ? { deliveryAttempts: input.deliveryAttempts } : {}),\n      ...(input.lastDeliveryAttemptAt !== undefined ? { lastDeliveryAttemptAt: input.lastDeliveryAttemptAt } : {}),\n      ...(input.lastDeliveryError !== undefined ? { lastDeliveryError: input.lastDeliveryError } : {}),\n      ...(input.deliveredSignalId !== undefined ? { deliveredSignalId: input.deliveredSignalId } : {}),\n      ...(input.summarySignalId !== undefined ? { summarySignalId: input.summarySignalId } : {}),\n      updatedAt: now,","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/notifications/storage.ts#L146-L182","documentation":"updateNotification looks up the notification by the (threadId, id) composite key in the in-memory map. If no record exists for that pair it throws this error instead of silently returning. This is an existence check to prevent phantom updates.","triggerScenarios":"Calling updateNotification with an id that was never created, an id belonging to a different thread, or after the record was deleted / storage was reset (in-memory storage loses data on restart).","commonSituations":"Using a stale notification id from a previous session; passing the wrong threadId (e.g. swapped thread and resource ids); restarting a dev server backed by in-memory NotificationsStorage and replaying old update calls.","solutions":["Confirm the id and threadId pair matches an existing record by listing notifications first (storage.listNotifications({ threadId }))","Persist notifications with a durable storage adapter instead of in-memory storage if updates span process restarts","Guard updates: fetch the record, check it exists, then update","Verify you are not confusing threadId with resourceId in the input"],"exampleFix":"// before\nawait storage.updateNotification({ threadId: wrongThread, id: notificationId, status: 'seen' });\n// after\nconst [existing] = await storage.listNotifications({ threadId: correctThread, id: notificationId });\nif (existing) await storage.updateNotification({ threadId: correctThread, id: notificationId, status: 'seen' });","handlingStrategy":"try-catch","validationCode":"const existing = await storage.listNotifications({ threadId, id });\nif (!existing.length) return null; // skip update","typeGuard":"function isNotFoundForThread(e: unknown, threadId: string, id: string): boolean {\n  return e instanceof Error && e.message === `Notification ${id} was not found for thread ${threadId}`;\n}","tryCatchPattern":"try {\n  await storage.updateNotification({ threadId, id, status: 'seen' });\n} catch (e) {\n  if (isNotFoundForThread(e, threadId, id)) {\n    logger.warn('Notification already gone, skipping update', { threadId, id });\n    return;\n  }\n  throw e;\n}","preventionTips":["Fetch-then-update to confirm existence before updating","Use durable storage instead of in-memory storage across restarts","Never reuse notification ids across threads"],"tags":["notifications","not-found","storage"],"backgroundTag":"resource-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}