{"record":{"id":"5c5c8b9caf4b8550","repo":"VectifyAI/PageIndex","slug":"offset-must-be-non-negative-5c5c8b","errorCode":null,"errorMessage":"offset must be non-negative","messagePattern":"offset must be non-negative","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pageindex/local_api.py","lineNumber":354,"sourceCode":"            raise PageIndexAPIError(\"Failed to get document metadata: Document not found\")\n        return {key: meta.get(key) for key in\n                (\"id\", \"name\", \"description\", \"status\", \"createdAt\", \"pageNum\", \"folderId\")}\n\n    def delete_document(self, doc_id: str) -> dict[str, Any]:\n        if not self._store.delete_document(doc_id):\n            raise PageIndexAPIError(\"Failed to delete document: Document not found.\")\n        return {\"message\": \"Document deleted successfully.\"}\n\n    def list_documents(\n        self,\n        limit: int = 50,\n        offset: int = 0,\n        folder_id: str | None = None,\n    ) -> dict[str, Any]:\n        if limit < 1 or limit > 100:\n            raise ValueError(\"limit must be between 1 and 100\")\n        if offset < 0:\n            raise ValueError(\"offset must be non-negative\")\n        if folder_id is not None:\n            raise PageIndexAPIError(\n                \"Failed to list documents: folders are not supported in local mode.\"\n            )\n        metas = sorted(self._store.list_metas(), key=lambda m: m.get(\"id\") or \"\")\n        metas.sort(key=lambda m: m.get(\"createdAt\") or \"\", reverse=True)\n        documents = [{\n            \"id\": m.get(\"id\"),\n            \"name\": m.get(\"name\"),\n            \"description\": m.get(\"description\"),\n            \"status\": m.get(\"status\"),\n            \"createdAt\": m.get(\"createdAt\"),\n            \"pageNum\": m.get(\"pageNum\", 0),\n            \"folderId\": None,\n            \"metadata\": m.get(\"metadata\"),\n            \"features\": {},\n        } for m in metas[offset:offset + limit]]\n        return {","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/VectifyAI/PageIndex/blob/afb5e119766630af6014b04fe8b53357527bc05e/pageindex/local_api.py#L336-L372","documentation":"list_documents requires a non-negative offset; negative offsets are rejected with ValueError before any store access. Offset is a skip count, not an index, so -1 'last item' semantics are unsupported.","triggerScenarios":"Calling list_documents(offset=-1) or passing an offset computed as start_index - page_size that goes negative on the first page.","commonSituations":"Off-by-one in cursor math, converting from 1-based page numbers incorrectly (page-1)*size when page=0, mirroring SQL OFFSET tricks.","solutions":["Clamp offset: offset = max(0, computed_offset)","Fix page-number conversion to (page - 1) * limit with 1-based pages","Guard pagination inputs before calling"],"exampleFix":"# before\nclient.list_documents(offset=page * -10)\n\n# after\nclient.list_documents(offset=max(0, (page - 1) * 50))","handlingStrategy":"validation","validationCode":"offset = max(0, int(offset or 0))\nclient.list_documents(limit=limit, offset=offset)","typeGuard":"def is_valid_offset(offset) -> bool:\n    return isinstance(offset, int) and not isinstance(offset, bool) and offset >= 0","tryCatchPattern":"null","preventionTips":["Compute offset as max(0, (page-1)*limit)","Unit-test first-page pagination math","Validate pagination params at the request boundary"],"tags":["pageindex","pagination","validation","valueerror"],"backgroundTag":"pagination-offset-invalid","analyzedSha":"afb5e119766630af6014b04fe8b53357527bc05e","analyzedAt":"2026-08-27T11:20:48.519Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}