{"record":{"id":"27fdbf491493e6ab","repo":"mastra-ai/mastra","slug":"attention-read-all-response-is-missing-its-continu","errorCode":null,"errorMessage":"Attention read-all response is missing its continuation cursor.","messagePattern":"Attention read-all response is missing its continuation cursor\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory-ui/src/ui/domains/factory/services/attention.ts","lineNumber":111,"sourceCode":"  item: FactoryAttentionItem,\n  action: FactoryAttentionReceiptAction,\n): Promise<{ receipt: { key: string; state: 'read' | 'archived'; readAt: string; archivedAt: string | null } }> {\n  return requestJson(\n    `${baseUrl}/web/factory/projects/${encodeURIComponent(factoryProjectId)}/attention/${item.kind}/${encodeURIComponent(attentionItemSourceId(item))}/${item.occurrence}/${action}`,\n    { method: 'POST' },\n  );\n}\n\nexport async function markAllFactoryAttentionRead(baseUrl: string, factoryProjectId: string): Promise<{ ok: true }> {\n  let before: string | undefined;\n  while (true) {\n    const query = before ? `?before=${encodeURIComponent(before)}` : '';\n    const page = await requestJson<{ ok: true; hasMore: boolean; nextCursor?: string }>(\n      `${baseUrl}/web/factory/projects/${encodeURIComponent(factoryProjectId)}/attention/read-all${query}`,\n      { method: 'POST' },\n    );\n    if (!page.hasMore) return { ok: true };\n    if (!page.nextCursor) throw new Error('Attention read-all response is missing its continuation cursor.');\n    before = page.nextCursor;\n  }\n}\n","sourceCodeStart":93,"sourceCodeEnd":115,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory-ui/src/ui/domains/factory/services/attention.ts#L93-L115","documentation":"markAllFactoryAttentionRead pages through the attention read-all endpoint; when a page reports hasMore=true but omits nextCursor, the continuation cursor needed to keep marking items read is missing, so it throws rather than silently stopping or looping forever. This is a strict server-response invariant check against inconsistent API responses.","triggerScenarios":"POST /web/factory/projects/:id/attention/read-all?before=... returns { ok:true, hasMore:true } without nextCursor — server bug, version skew between client expectations and API, or a proxy altering the response body.","commonSituations":"API deployed with pagination behavior changed while the frontend expects the old contract; gateway/response transform stripping optional fields; partial rollout where the endpoint version differs from the client.","solutions":["Inspect the raw read-all response confirming hasMore=true with no nextCursor; report/fix the server to always return nextCursor when hasMore is true.","Align frontend and API versions (deploy both together).","Check for any response-transforming middleware/proxy stripping fields.","As a caller, catch and surface the error; re-running markAll after the server fix resumes marking items read."],"exampleFix":"// before (server)\nreturn Response.json({ ok: true, hasMore: true });\n// after (server)\nreturn Response.json({ ok: true, hasMore: true, nextCursor: oldestUnreadTs });","handlingStrategy":"try-catch","validationCode":"if (page.hasMore && typeof page.nextCursor !== 'string') throw new Error('Response cursor invariant violated');","typeGuard":"function isReadAllPage(v: unknown): v is { ok: true; hasMore: boolean; nextCursor?: string } {\n  if (typeof v !== 'object' || v === null) return false;\n  const o = v as Record<string, unknown>;\n  return o.ok === true && typeof o.hasMore === 'boolean' && (o.nextCursor === undefined || typeof o.nextCursor === 'string');\n}","tryCatchPattern":"try {\n  await markAllFactoryAttentionRead(baseUrl, projectId);\n} catch (e) {\n  showToast('Could not mark all as read; some items may remain unread.');\n  console.error(e); // invariant violation: server sent hasMore without nextCursor\n}","preventionTips":["Enforce server-side: nextCursor is always present when hasMore is true.","Deploy client and API pagination changes together.","Integration-test the read-all pagination loop."],"tags":["pagination","api-contract","invariant","http"],"backgroundTag":"missing-continuation-cursor","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}