{"record":{"id":"b3e741326abb67a4","repo":"toeverything/AFFiNE","slug":"invalid-cursor","errorCode":"INVALID_CURSOR","errorMessage":"Invalid canvas cursor.","messagePattern":"Invalid canvas cursor\\.","errorType":"error_code","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/backend/server/src/plugins/copilot/tools/doc-canvas-read.ts","lineNumber":246,"sourceCode":"    const canAccess = await ac\n      .user(options.user)\n      .workspace(options.workspace)\n      .doc(docId)\n      .can('Doc.Read');\n    if (!canAccess) {\n      return toolError('Doc Canvas Read Failed', 'Document access denied.', {\n        code: 'DOC_ACCESS_DENIED',\n        retryable: false,\n        locator: { doc_id: docId },\n      });\n    }\n    const projection = await docReader.getDocCanvas(options.workspace, docId);\n    if (!projection) {\n      return documentSyncPendingError(docId);\n    }\n    const cursor = cursorValue ? decodeCursor(cursorValue) : null;\n    if (cursorValue && !cursor) {\n      return toolError('Doc Canvas Read Failed', 'Invalid canvas cursor.', {\n        code: 'INVALID_CURSOR',\n        retryable: false,\n        locator: { doc_id: docId },\n      });\n    }\n    const fingerprint = targetHash(target);\n    if (\n      cursor &&\n      (cursor.projectionVersion !== projection.version ||\n        cursor.revision !== projection.revision ||\n        cursor.targetHash !== fingerprint)\n    ) {\n      return toolError(\n        'Doc Canvas Read Failed',\n        'The document changed after this cursor was issued.',\n        {\n          code: 'REVISION_CHANGED',\n          retryable: true,","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/toeverything/AFFiNE/blob/b4c8548c09da21b2898443559a5b846f0ccf5dd8/packages/backend/server/src/plugins/copilot/tools/doc-canvas-read.ts#L228-L264","documentation":"decodeCursor could not parse the supplied pagination cursor (malformed or corrupt base64/JSON), so the getter returns a non-retryable INVALID_CURSOR tool error; an absent cursor is fine (first page), only a provided-but-unparseable one fails.","triggerScenarios":"Returned as INVALID_CURSOR when a cursor value is supplied to doc_canvas_read but decodeCursor fails to parse it.","commonSituations":"A corrupted or hand-edited pagination cursor was passed to the canvas read. Restart the read without a cursor to get a fresh one.","solutions":["Discard the cursor and start a new canvas read.","Do not reuse cursors across sessions."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"b4c8548c09da21b2898443559a5b846f0ccf5dd8","analyzedAt":"2026-08-18T21:16:52.546Z","contentChangedAt":"2026-08-18T21:16:52.546Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}