{"record":{"id":"ac93331aecb6f908","repo":"mastra-ai/mastra","slug":"could-not-resolve-cursor-message-cursor","errorCode":null,"errorMessage":"Could not resolve cursor message: ${cursor}","messagePattern":"Could not resolve cursor message: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/memory/src/tools/om-tools.ts","lineNumber":148,"sourceCode":"\n  const rangeIds = parseRangeFormat(normalized);\n  if (rangeIds) {\n    return {\n      hint: `The cursor \"${cursor}\" looks like a range. Use one of the individual message IDs as the cursor instead: start=\"${rangeIds.startId}\" or end=\"${rangeIds.endId}\".`,\n      ...rangeIds,\n    };\n  }\n\n  const memoryStore = await memory.getMemoryStore();\n  const result = await memoryStore.listMessagesById({ messageIds: [normalized] });\n  let message = result.messages.find(message => message.id === normalized) ?? null;\n\n  if (!message) {\n    message = await resolveCursorMessageByRecall(memory, normalized, access);\n  }\n\n  if (!message) {\n    throw new Error(`Could not resolve cursor message: ${cursor}`);\n  }\n\n  // Verify the cursor message belongs to the current resource\n  if (access?.resourceId && message.resourceId !== access.resourceId) {\n    throw new Error(`Could not resolve cursor message: ${cursor}`);\n  }\n\n  // In strict thread scope, verify the cursor belongs to the current thread\n  if (access?.enforceThreadScope && access.threadScope && message.threadId !== access.threadScope) {\n    throw new Error(`Could not resolve cursor message: ${cursor}`);\n  }\n\n  return message;\n}\n\nasync function resolveCursorMessageByRecall(\n  memory: RecallMemory,\n  cursor: string,","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/memory/src/tools/om-tools.ts#L130-L166","documentation":"After trimming, `resolveCursorMessage` looks the cursor up directly via `memoryStore.listMessagesById`, then falls back to scanning the resource's threads via `resolveCursorMessageByRecall`. If no stored message matches the ID, it throws this error. The same message is deliberately reused for access-control failures so callers cannot probe for foreign message IDs.","triggerScenarios":"cursor is a message ID that does not exist in the store; the ID belongs to another resource while access.resourceId is set; the ID belongs to a different thread while enforceThreadScope is true; a stale cursor from a deleted thread; a typo'd or hallucinated (LLM-invented) ID.","commonSituations":"Cursor carried across environments (dev DB id used against prod); memory store wiped or thread garbage-collected between calls; multi-tenant app querying with the wrong resourceId in the access context; an LLM guessing a plausible-looking message ID.","solutions":["Re-list messages for the thread (recall page 1) and copy an exact messageId from the response as the new cursor.","Confirm the resourceId/threadScope passed in the access context matches the thread the cursor came from.","Check the message still exists (thread may have been deleted or trimmed); start a fresh recall if the thread is gone.","Do not use a range cursor (start:end) here — that yields the range-hint error; pick one endpoint ID."],"exampleFix":"// before\nawait recallMessages({ memory, threadId, cursor: 'msg_from_other_thread' });\n// after\nconst page = await recallMessages({ memory, threadId, page: 1 });\nconst validId = JSON.parse(page.messages)[0].messageId;\nawait recallMessages({ memory, threadId, cursor: validId });","handlingStrategy":"fallback","validationCode":"// Verify the cursor exists in the thread before using it\nconst page = await recallMessages({ memory, threadId, resourceId, page: 1 });\nconst known = JSON.parse(page.messages).some(m => m.messageId === cursor);\nif (!known) { cursor = JSON.parse(page.messages).at(-1)?.messageId; }","typeGuard":null,"tryCatchPattern":"try {\n  return await recallMessages({ memory, threadId, resourceId, cursor });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Could not resolve cursor message')) {\n    return recallMessages({ memory, threadId, resourceId, page: 1 }); // restart from the beginning\n  }\n  throw e;\n}","preventionTips":["Store cursors with the resourceId/threadId they were issued for.","Never let the model invent message IDs; require verbatim reuse from tool output.","Handle deleted/trimmed threads by restarting recall from page 1."],"tags":["memory","cursor","not-found","observational-memory"],"backgroundTag":"resource-not-found","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}