{"record":{"id":"086cf345f8473868","repo":"appwrite/appwrite","slug":"general-cursor-not-found-086cf3","errorCode":"general_cursor_not_found","errorMessage":"Deployment '{$deploymentId}' for the 'cursor' value not found.","messagePattern":"Deployment '(.+?)' for the 'cursor' value not found\\.","errorType":"exception","errorClass":"Appwrite\\Extend\\Exception","httpStatus":400,"severity":"error","filePath":"src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php","lineNumber":112,"sourceCode":"\n        // Set resource queries\n        $queries[] = Query::equal('resourceInternalId', [$function->getSequence()]);\n        $queries[] = Query::equal('resourceType', ['functions']);\n\n        $cursor = Query::getCursorQueries($queries, false);\n        $cursor = \\reset($cursor);\n\n        if ($cursor !== false) {\n            $validator = new Cursor();\n            if (!$validator->isValid($cursor)) {\n                throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());\n            }\n\n            $deploymentId = $cursor->getValue();\n            $cursorDocument = $dbForProject->getDocument('deployments', $deploymentId);\n\n            if ($cursorDocument->isEmpty()) {\n                throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, \"Deployment '{$deploymentId}' for the 'cursor' value not found.\");\n            }\n\n            $cursor->setValue($cursorDocument);\n        }\n\n        $grouped = Query::groupByType($queries);\n        $filterQueries = $grouped['filters'];\n        $selectQueries = $grouped['selections'];\n\n        try {\n            $results = $dbForProject->find('deployments', $queries);\n            $total = $includeTotal ? $dbForProject->count('deployments', $filterQueries, APP_LIMIT_COUNT) : 0;\n        } catch (OrderException $e) {\n            throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, \"The order attribute '{$e->getAttribute()}' had a null value. Cursor pagination requires all documents order attribute values are non-null.\");\n        } catch (QueryException $e) {\n            throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());\n        }\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/appwrite/appwrite/blob/a1d520eea492ebd1da1ef2dc8db5b2b34e277dce/src/Appwrite/Platform/Modules/Functions/Http/Deployments/XList.php#L94-L130","documentation":"The cursor value passed syntax validation, but the deployments lookup for that ID returned an empty document: the cursor deployment was deleted (retention cleanup, concurrent delete) or never existed. Cursor pagination anchors to an existing neighbor document, so the query cannot proceed.","triggerScenarios":"Cursor references a deployment removed by retention or a concurrent DELETE between two pages; cursor reused from a stale cached list response; cursor ID typo'd or from another project/function.","commonSituations":"Long-running pagination over deployments while builds churn and old rows are purged; resuming pagination sessions from cached state; sharing cursors across environments.","solutions":["Restart pagination from the first page without the cursor","Always use a cursor taken from the most recent list response","Raise deployments retention or complete pagination faster than cleanup runs","Fall back to limit/offset paging when a stable snapshot is acceptable"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Use cursors only from a list response fetched moments ago:\nconst page = await functions.listDeployments({ functionId, queries: [Query.limit(25)] });\nconst last = page.deployments.at(-1);\nif (!last) return; // empty page — done\nconst next = await functions.listDeployments({\n  functionId,\n  queries: [Query.cursorAfter(last.$id), Query.limit(25)],\n});","typeGuard":null,"tryCatchPattern":"try {\n  const res = await functions.listDeployments({ functionId, queries });\n} catch (e) {\n  if (e?.code === 'general_cursor_not_found') {\n    // Cursor deployment was deleted — restart from page one without the cursor.\n  }\n  throw e;\n}","preventionTips":["Do not persist cursors across long-lived sessions","Complete pagination faster than retention deletes rows, or page by $createdAt ranges instead"],"tags":["appwrite","query","pagination","cursor","deployments","not-found"],"backgroundTag":"invalid-pagination-cursor","analyzedSha":"a1d520eea492ebd1da1ef2dc8db5b2b34e277dce","analyzedAt":"2026-08-18T21:34:56.994Z","contentChangedAt":"2026-08-18T21:34:56.994Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}