Skip to content

Bug Report: Async pagination returns duplicates when iterating over blocks #63

@marklubin

Description

@marklubin

Summary

When using async for to iterate over client.agents.blocks.list(), duplicate items are returned. An agent with 6 blocks yields 21 items.

Environment

  • Package: letta-client 1.6.1 (from PyPI)
  • Python: 3.12
  • Server: Self-hosted Docker (latest)

Reproduction

import asyncio
from letta_client import AsyncLetta

async def test():
    client = AsyncLetta(base_url='http://localhost:8283')
    agent_id = 'agent-...'  # Any agent with blocks

    count = 0
    async for block in client.agents.blocks.list(agent_id=agent_id):
        count += 1
        print(f'{count}. {block.label}')

    print(f'Total: {count}')  # Expect 6, get 21

asyncio.run(test())

Output:

1. human
2. persona
3. last_session_summary
4. background_insights
5. Apiana's Writ
6. focus
7. human           # duplicates start
8. persona
...
Total: 21

Analysis

We believe the issue is a mismatch between the SDK's cursor pagination logic and the server's default sort order:

  • The SDK's next_page_info() uses after=<last_item_id>, which assumes ascending order
  • The server defaults to descending order for this endpoint
  • With descending order, after=<oldest_item> returns items we've already seen

Evidence: Adding order='asc' fixes the issue completely:

async for block in client.agents.blocks.list(agent_id=agent_id, order='asc'):
    # Returns exactly 6 blocks, no duplicates

Workaround

We're explicitly passing order='asc' to all paginated list calls.

Thanks for taking a look!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions