{"record":{"id":"913bccb78969bc25","repo":"mastra-ai/mastra","slug":"invalid-knowledge-node-cursor","errorCode":null,"errorMessage":"Invalid knowledge node cursor.","messagePattern":"Invalid knowledge node cursor\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/storage/domains/knowledge/base.ts","lineNumber":189,"sourceCode":"      name: node.name,\n      id: node.id,\n      namePrefix: filters.namePrefix?.toLocaleLowerCase() ?? null,\n      kind: filters.kind ?? null,\n      hasContent: filters.hasContent ?? null,\n    }),\n  );\n}\n\n/** @experimental Knowledge APIs are experimental and may change without notice. */\nexport function parseKnowledgeNodeCursor(\n  cursor: string,\n  filters: { namePrefix?: string; kind?: string; hasContent?: boolean },\n): KnowledgeNodeCursor {\n  let value: unknown;\n  try {\n    value = JSON.parse(decodeURIComponent(cursor));\n  } catch {\n    throw new Error('Invalid knowledge node cursor.');\n  }\n  if (!value || typeof value !== 'object') throw new Error('Invalid knowledge node cursor.');\n  const parsed = value as Record<string, unknown>;\n  const updatedAt = typeof parsed.updatedAt === 'string' ? new Date(parsed.updatedAt) : new Date(Number.NaN);\n  if (\n    parsed.version !== 1 ||\n    parsed.type !== 'node' ||\n    typeof parsed.name !== 'string' ||\n    typeof parsed.id !== 'string' ||\n    Number.isNaN(updatedAt.getTime()) ||\n    parsed.namePrefix !== (filters.namePrefix?.toLocaleLowerCase() ?? null) ||\n    parsed.kind !== (filters.kind ?? null) ||\n    parsed.hasContent !== (filters.hasContent ?? null)\n  ) {\n    throw new Error('Knowledge node cursor does not match the active browse filters.');\n  }\n  return { updatedAt, name: parsed.name, id: parsed.id };\n}","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/core/src/storage/domains/knowledge/base.ts#L171-L207","documentation":"`parseKnowledgeNodeCursor` decodes and JSON-parses a pagination cursor and throws this generic message when parsing fails (JSON.parse error) or the result is not a plain object. Cursors are opaque tokens produced by the library; this error signals a malformed or hand-edited cursor. There are two throw sites — this one covers the parse/shape failure.","triggerScenarios":"Passing a cursor string that is not URL-encoded JSON (e.g. raw text, empty string, HTML from a bad link), or a value that decodes to a non-object (number, string, null).","commonSituations":"Client truncating the cursor in a URL query parameter; a proxy or framework decoding/re-encoding it incorrectly; storing cursors in a system that mangles special characters (%, {); hand-rolling a cursor instead of using the one returned by the previous page.","solutions":["Use the cursor exactly as returned by the previous `list`/page response — do not construct or edit it manually.","URL-encode the cursor when embedding it in a query string and decode it once on receipt.","Verify the client didn't truncate the cursor (they can be long); check request logs for the full value.","On this error, restart pagination from the beginning (omit the cursor) instead of retrying the same token."],"exampleFix":"// before\nconst cursor = rows[0].someField; // wrong field / hand-made\nconst page = await listNodes({ cursor });\n// after\nconst page1 = await listNodes({});\nconst page2 = await listNodes({ cursor: page1.nextCursor }); // opaque token reused verbatim","handlingStrategy":"try-catch","validationCode":"function looksLikeCursor(raw: unknown): raw is string {\n  if (typeof raw !== 'string' || raw.length === 0) return false;\n  try {\n    const decoded = JSON.parse(decodeURIComponent(raw));\n    return typeof decoded === 'object' && decoded !== null;\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isValidNodeCursor(raw: unknown): raw is string {\n  if (!looksLikeCursor(raw)) return false;\n  try {\n    const v = JSON.parse(decodeURIComponent(raw as string)) as Record<string, unknown>;\n    return v.version === 1 && v.type === 'node' && typeof v.name === 'string' && !Number.isNaN(new Date(v.updatedAt as string).getTime());\n  } catch {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  await listNodes({ cursor });\n} catch (e) {\n  if (e instanceof Error && e.message === 'Invalid knowledge node cursor.') {\n    // restart pagination from the beginning\n    return listNodes({});\n  }\n  throw e;\n}","preventionTips":["Treat cursors as opaque: never parse, edit, or construct them.","URL-encode cursors in query strings and decode exactly once.","Avoid storing cursors through layers that may truncate or re-escape characters.","Validate cursor presence/shape client-side before sending requests."],"tags":["storage","knowledge","pagination","cursor","validation"],"backgroundTag":"invalid-pagination-cursor","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}