{"record":{"id":"909ba6dde9ce0a37","repo":"mastra-ai/mastra","slug":"invalid-cursor","errorCode":"invalid-cursor","errorMessage":"Knowledge cursor does not match the active scope and filters.","messagePattern":"Knowledge cursor does not match the active scope and filters\\.","errorType":"error_code","errorClass":"KnowledgeInspectorError","httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/knowledge-inspector.ts","lineNumber":736,"sourceCode":"    cursor: string | undefined,\n    binding: Binding,\n    level: KnowledgeInspectorScopeLevel,\n    kind: CursorEntry['kind'],\n    filters?: CursorEntry['filters'],\n  ): string | undefined {\n    if (!cursor) return undefined;\n    const entry = this.#cursors.get(cursor);\n    if (\n      !entry ||\n      entry.expiresAt < Date.now() ||\n      entry.identityKey !== binding.identityKey ||\n      entry.level !== level ||\n      entry.kind !== kind ||\n      entry.filters?.namePrefix !== filters?.namePrefix ||\n      entry.filters?.kind !== filters?.kind ||\n      entry.filters?.sort !== filters?.sort\n    ) {\n      throw new KnowledgeInspectorError(\n        'invalid-cursor',\n        'Knowledge cursor does not match the active scope and filters.',\n      );\n    }\n    return entry.value;\n  }\n\n  #pruneOpaqueEntries(): void {\n    const now = Date.now();\n    for (const [token, entry] of this.#handles) {\n      if (entry.expiresAt < now) this.#handles.delete(token);\n    }\n    for (const [token, entry] of this.#cursors) {\n      if (entry.expiresAt < now) this.#cursors.delete(token);\n    }\n    while (this.#handles.size + this.#cursors.size >= MAX_OPAQUE_ENTRIES) {\n      const handle = this.#handles.keys().next().value;\n      if (handle) this.#handles.delete(handle);","sourceCodeStart":718,"sourceCodeEnd":754,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/knowledge-inspector.ts#L718-L754","documentation":"Pagination cursors are opaque tokens bound to identityKey, scope level, kind (nodes/activity), and the exact filters (namePrefix, kind, sort). #consumeCursor() throws 'invalid-cursor' if the cursor is unknown, expired, from a different scope/level, or if any filter differs from the original query. Cursors cannot be reused across differently-filtered requests.","triggerScenarios":"Passing a nextCursor from a listNodes query into a subsequent call with changed namePrefix/kind/sort or a different level; reusing a cursor after a scope change (identityKey rotation); using a cursor after TTL expiry or cap eviction.","commonSituations":"UI changing the sort/filter while a 'load more' uses the old cursor; sharing cursors between org- and thread-level views; paginating hours later after the cursor expired.","solutions":["Keep namePrefix/kind/sort/level identical to the request that minted the cursor; if filters change, restart pagination without a cursor.","Catch KnowledgeInspectorError 'invalid-cursor', drop the cursor, and re-issue the first page.","Use cursors soon after minting; never persist them across sessions or scope switches."],"exampleFix":"// before\nawait inspector.listNodes({ level: 'resource', sort: 'recent', cursor: cursorForSortConnected });\n// after\nawait inspector.listNodes({ level: 'resource', sort: 'connected', cursor: cursorForSortConnected }); // filters match minting request","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await inspector.listNodes({ level, namePrefix, kind, sort, cursor });\n} catch (e) {\n  if (e instanceof KnowledgeInspectorError && e.code === 'invalid-cursor') {\n    return inspector.listNodes({ level, namePrefix, kind, sort }); // restart pagination from page 1\n  }\n  throw e;\n}","preventionTips":["Freeze filter state (namePrefix, kind, sort, level) while a cursor is in use; changing filters resets pagination.","Store cursor together with the exact query params that minted it and verify before reuse.","Expire client-side pagination state with the session/scope, not across restarts."],"tags":["knowledge-inspector","pagination","cursor-mismatch"],"backgroundTag":"invalid-pagination-cursor","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}