Pagination Issue: Duplicate Order in GraphQL orders Query

I’m using /admin/api/2024-10/graphql.json to retrieve a list of orders from the store.

My first query and response:

{
    orders(
        first: 10
        sortKey: CREATED_AT
        query: "updated_at:>2024-12-21T08:57:18.017987+01:00 updated_at:<2025-03-21T09:57:18.017987+01:00"
    ) {
        nodes {
            name
        }
        pageInfo {
            hasNextPage
            endCursor
            hasPreviousPage
            startCursor
        }
    }
}

{
    "data": {
        "orders": {
            "nodes": [
                {
                    "name": "#1434"
                },
                {
                    "name": "#1435"
                },
                {
                    "name": "#1436"
                },
                {
                    "name": "#1437"
                },
                {
                    "name": "#1439"
                },
                {
                    "name": "#1440"
                },
                {
                    "name": "#1441"
                },
                {
                    "name": "#1442"
                },
                {
                    "name": "#1448"
                },
                {
                    "name": "#1457",
                    "id": "gid://shopify/Order/6196834992409"
                }
            ],
            "pageInfo": {
                "hasNextPage": true,
                "endCursor": "eyJsYXN0X2lkIjo2MTk2ODM0OTkyNDA5LCJsYXN0X3ZhbHVlIjoxNzM3NjQxODA0MDAwfQ==",
                "hasPreviousPage": false,
                "startCursor": "eyJsYXN0X2lkIjo2MTkzMDEyMDQ4MTUzLCJsYXN0X3ZhbHVlIjoxNzM3Mzk2MTE0MDAwfQ=="
            }
        }
    },
    "extensions": {
        "cost": {
            "requestedQueryCost": 6,
            "actualQueryCost": 6,
            "throttleStatus": {
                "maximumAvailable": 2000,
                "currentlyAvailable": 1994,
                "restoreRate": 100
            }
        },
        "search": [
            {
                "path": [
                    "orders"
                ],
                "query": "updated_at:>2024-12-21T08:57:18.017987+01:00 updated_at:<2025-03-21T09:57:18.017987+01:00",
                "parsed": {
                    "and": [
                        {
                            "field": "updated_at",
                            "range_gt": "2024-12-21T00:00:00-05:00",
                            "range_lt": "2025-03-21T23:59:59-04:00"
                        },
                        {
                            "field": "default",
                            "match_all": "00"
                        },
                        {
                            "field": "57",
                            "match_all": "18.017987+01"
                        }
                    ]
                },
                "warnings": [
                    {
                        "field": "57",
                        "message": "Invalid search field for this query."
                    }
                ]
            }
        ]
    }
}

Then, I use the endCursor from pageInfo to fetch the next page:

{
    orders(
        first: 10
        after: "eyJsYXN0X2lkIjo2MTk2ODM0OTkyNDA5LCJsYXN0X3ZhbHVlIjoxNzM3NjQxODA0MDAwfQ=="
    ) {
        nodes {
            name
        }
        pageInfo {
            hasNextPage
            endCursor
            hasPreviousPage
            startCursor
        }
    }
}
{
    "data": {
        "orders": {
            "nodes": [
                {
                    "name": "#1457",
                    "id": "gid://shopify/Order/6196834992409"
                },
                {
                    "name": "#1458"
                },
                {
                    "name": "#1459"
                },
                {
                    "name": "#1460"
                },
                {
                    "name": "#1461"
                },
                {
                    "name": "#1462"
                },
                {
                    "name": "#1463"
                },
                {
                    "name": "#1464"
                },
                {
                    "name": "#1465"
                },
                {
                    "name": "#1466"
                }
            ],
            "pageInfo": {
                "hasNextPage": true,
                "endCursor": "eyJsYXN0X2lkIjo2MTk4MDQwMDAyODQxLCJsYXN0X3ZhbHVlIjoiMjAyNS0wMS0yNCAxMjowNToxMC41MDIxMzEifQ==",
                "hasPreviousPage": true,
                "startCursor": "eyJsYXN0X2lkIjo2MTk2ODM0OTkyNDA5LCJsYXN0X3ZhbHVlIjoiMjAyNS0wMS0yMyAxNDoxNjo0NC4zNTQ5OTYifQ=="
            }
        }
    },
    "extensions": {
        "cost": {
            "requestedQueryCost": 6,
            "actualQueryCost": 6,
            "throttleStatus": {
                "maximumAvailable": 2000,
                "currentlyAvailable": 1994,
                "restoreRate": 100
            }
        }
    }
}

However, the response contains #1457 again
As per the documentation, after should return elements after the given cursor, meaning #1457 should not appear again in the next page. pagination

If I continue paginating using after with the next cursors, after a few iterations, the behavior corrects itself. At that point, the last element from the previous page no longer appears at the beginning of the next page, and pagination works as expected.

  1. Am I misunderstanding how pagination works with after?
  2. Could this be an issue with sorting or how the cursor is encoded?
  3. Is there a way to ensure that duplicate results do not appear when paginating?

Can you add sortKey: CREATED_AT in the second GraphQL query and try again?

Yes, I did that. It didn’t help.

Can you also include updatedAt in the query to see if #1457 was updated again?

Just a note - you sorted by CREATED_AT but filtered by updated_at there is no guarantee that the order won’t be duplicated since the order updatedAt should be changed.

1 Like

If I use

    orders(
        first: 10
        sortKey: CREATED_AT
        after: "eyJsYXN0X2lkIjo2MTk2ODM0OTkyNDA5LCJsYXN0X3ZhbHVlIjoxNzM3NjQxODA0MDAwfQ=="
        query: "updated_at:>2024-12-21T08:57:18.017987+01:00 updated_at:<2025-03-21T09:57:18.017987+01:00"
    )

it returns the correct answer

            "nodes": [
                {
                    "name": "#1458"
                },
                {
                    "name": "#1459"
                },
                {
                    "name": "#1460"
                },
                {
                    "name": "#1461"
                },
                {
                    "name": "#1462"
                },
                {
                    "name": "#1463"
                },
                {
                    "name": "#1464"
                },
                {
                    "name": "#1465"
                },
                {
                    "name": "#1466"
                },
                {
                    "name": "#1467"
                }
            ]

In this case, I must continuously use all parameters with a changeable cursor.
I don’t think this is how the cursor should work

When paginating through orders using the cursor, you need to include the original query parameter along with the cursor.