mastra-ai/mastra · error
The cursor "${cursor}" looks like a range. Use one of the in
Error message
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}". What it means
Cursors must be a single message ID. `parseRangeFormat` detects range-shaped cursors like "startId:endId" or "id1:id2,id3:id4" (the internal format of merged ranges) and `resolveCursorMessage` returns a hint object; the detail-recall path converts that hint into this thrown error. The hint itself contains the correct start/end IDs to use instead.
Source
Thrown at packages/memory/src/tools/om-tools.ts:805
nextCharOffset?: number;
note?: string;
}> {
if (!memory || typeof memory.getMemoryStore !== 'function') {
throw new Error('Memory instance is required for recall');
}
if (!threadId) {
throw new Error('Thread ID is required for recall');
}
const resolved = await resolveCursorMessage(memory, cursor, {
resourceId,
threadScope,
enforceThreadScope: false,
});
if ('hint' in resolved) {
throw new Error(resolved.hint);
}
const allParts = formatMessageParts(resolved, 'high');
if (allParts.length === 0) {
throw new Error(
`Message ${cursor} has no visible content (it may be an internal system message). Try a neighboring message ID instead.`,
);
}
const target = [...allParts].reverse().find(p => p.partIndex === partIndex);
if (!target) {
const availableIndices = allParts.map(p => p.partIndex).join(', ');
const highestVisiblePartIndex = Math.max(...allParts.map(p => p.partIndex));
if (partIndex > highestVisiblePartIndex) {
const nextMessage = await getNextVisibleMessage({View on GitHub (pinned to 75dd419e61)
Solutions
- Parse the error message: it names start="..." and end="..." — use one of those individual IDs as the cursor.
- Use the start ID to recall forward from the beginning of the range, or the end ID to end at it.
- Never pass multi-message range strings to the recall cursor parameter; ranges are internal to observational-memory processing.
- If the model keeps doing this, add an example in the tool description showing a single plain message ID.
Example fix
// before
await recallMessages({ memory, threadId, cursor: 'msg_1:msg_50' });
// after
await recallMessages({ memory, threadId, cursor: 'msg_1' }); Defensive patterns
Strategy: validation
Validate before calling
function isSingleMessageId(cursor: string): boolean {
return cursor.trim().length > 0 && !cursor.includes(':') && !cursor.includes(',');
}
if (!isSingleMessageId(cursor)) throw new Error('Use a single message ID, not a start:end range.'); Try / catch
try {
return await recallDetail({ memory, threadId, cursor, partIndex });
} catch (e) {
const m = e instanceof Error && /start="([^"]+)" or end="([^"]+)"/.exec(e.message);
if (m) {
return recallDetail({ memory, threadId, cursor: m[1], partIndex }); // use the start ID
}
throw e;
} Prevention
- Only copy cursor values from recall responses' messageId fields.
- Strip or reject ':' and ',' in cursors at your tool wrapper.
- Document in the tool description that cursor is one message ID, never a range.
When it happens
Trigger: Passing a range cursor copied from internal/observational-memory state (e.g. "msgA:msgB") into the recall tool's cursor argument; an LLM echoing back a range it saw in tool output instead of one endpoint ID.
Common situations: Piping output from another om feature that emits ranges directly into recall; hand-building cursors by concatenating two IDs; model misreading the cursor documentation.
Related errors
- Cursor is required
- Could not resolve cursor message: ${cursor}
- Message ${cursor} has no visible content (it may be an inter
- AGENT_NETWORK_OBSERVATIONAL_MEMORY_UNSUPPORTED
- Observational memory record not found: ${currentRecord.id}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/5687b2bc418cc252.
Report an issue: GitHub.