Inconsistent results from Admin GraphQL productVariants query with collection filter

Hi everyone,

I’m seeing inconsistent behavior with the Admin GraphQL API when querying productVariants using a collection filter, and I wanted to report it to see if others have encountered the same issue or if there’s something I might be missing.

Issue Description

When sending the exact same productVariants query multiple times, the results are inconsistent:

  • The first request returns many results as expected

  • A subsequent request (sent immediately after) returns no results

  • Changing the first parameter does not resolve the issue

This happens without any changes to products, collections, or permissions in between requests.

Query Used

{
  productVariants(
    first: 250
    query: "(collection:'457565962493' OR collection:'457747562749' OR collection:'457607741693' OR collection:'457602269437' OR collection:'457607643389' OR collection:'457607676157' OR collection:'457606725885' OR collection:'457606824189' OR collection:'457602007293' OR collection:'457602040061' OR collection:'457602105597')"
  ) {
    nodes {
      id
    }
  }
}

Observed Behavior

  1. First request

    • :white_check_mark: Returned many results

    • Request ID:
      ef19f4d0-6214-4c23-8b8b-9638ed7764f8-1767780377

  2. Second request (same query, sent immediately after)

    • :cross_mark: Returned no results

    • Request ID:
      546fdfb1-d825-4651-86f6-56965b66f6f9-1767780334

  3. After changing first from 250 to 10

    {
      productVariants(
        first: 10
        query: "(collection:'457565962493' OR collection:'457747562749' OR collection:'457607741693' OR collection:'457602269437' OR collection:'457607643389' OR collection:'457607676157' OR collection:'457606725885' OR collection:'457606824189' OR collection:'457602007293' OR collection:'457602040061' OR collection:'457602105597')"
      ) {
        nodes {
          id
        }
      }
    }
    
    
    • :cross_mark: Still returned no results

    • Request ID:
      fced003d-6f92-494b-84c3-0aa6f03d18c7-1767780445

Expected Behavior

The same query should consistently return the same set of product variants, assuming no underlying data changes.

Additional Notes

  • No rate limiting errors were returned

  • The app has full read access to products and collections

  • Are there any known limitations or best practices when using multiple collection filters with productVariants?

Thanks in advance for any insights :folded_hands:

Hi @RorySeka

I can confirm that this is a known issue that our developers are aware of, filtering by collection on productVariant queries and connectors.

We do have an ongoing thread for this here, so I will be closing this thread and you can follow along here instead for updates:

Additionally as a workaround I would recommend utilizing the collections query instead, which is still returning the correct products and variants as expected.

Hi @Kellan-Shopify I appreciate your time on this issue but want to note that the workaround you have suggested is not a dependable solution for the reasons shared here: productVariants GraphQL endpoint incorrect results - #7 by Chris_Geelhoed

Hi @Chris_Geelhoed,

Just to confirm, is your concern with the query cost? If so I’ve tested this on my own store, with a productVariants query that returns the expected amount of variants, and a collections query that returns the same amount of variants.

As we can see in the examples below, the actualQueryCost of the productVariants query I ran is more than the actualQueryCost of the collections query, when requesting only 20 product variants.

However the requestedQueryCost is higher due to the amount requested in all connections.

This is because the requestedQueryCost is calculated based on the total amount requested for all edges, even if that amount doesn’t exist on the store.

For example in the collections query, I requested 250, even though I know it will return 1 collection since I’m filtering by a single collection id.

If I reduce the first amount in the collections arguments, we can see that the requestedQueryCost is significantly lowered.

As for how this affects your rate limit, this is explained in further detail in the Shopify.dev documentation:

TLDR:

  • rate limits use a combination of the requested cost, and the actual cost, when determining if your app’s rate point bucket has enough to complete the request, but then refunds the difference back to the bucket afterwards so it only uses the amount of the actual cost.

This means that you can use the workaround with the collections query, and reduce the cost of the query by reducing the amount requested in the first argument for each connector.

You should only be requesting the expected or lower amount of resources per connector, instead of just requesting the maximum limit of 250 per. You can then utilize pagination to request more if needed.

With that all said, as this is a duplicate issue from the thread that you linked, I will leave this thread marked as solved for now, and any further questions or comments on this issue can be addressed on the existing thread here:

Hi Kellan,

Thanks for the additional insight on this.

I appreciate your example, but those queries make some assumptions that app developers can’t make in production apps.

Let’s say that an app needs to get all the product variants from a collection in pages, 250 at a time.

In the productVariants endpoint this is relatively easy. We can fetch pages of product variants 250 at a time using first: 250 and then make additional requests with the using “after” with the last edge’s cursor as needed.

The workaround you have suggested does not work this way, because there is additional nesting (there are edges inside of edges)

Your query assumes that there is 1 product variant in a product. When querying an arbitrary collection, this is an assumption app devs cannot make. There could be 1 to 2048 variants, and the app needs to work with anything in that range. The max pagination limit is 250.

We also need to consider the product edges. If we try to fetch 250 products with 250 variants, the query cost will be too high to run this query practically. Not to mention, we can’t get a clean 250 item pagination chunk. We could fetch like 15 (sqrt of 250) products with the first 15 variants and manage the cursor of both the inner and outer edges to achieve the same thing we did before, but now our complexity has gone up and our performance has gone down.

Even beyond the query cost/performance issue, this workaround does not work because it will return the wrong variants in some cases. Copying and pasting from the example I shared earlier:

Also, that query does not give the same results in many cases and using it will lead to other bugs. Here is a concrete example:

  1. Merchant has products that have multiple variants. Let’s say a product has 3 variants priced at $5, $12, and $20 for different sizes.
  2. Merchant creates an automated collection which includes all product variants under $10
  3. Merchant uses an app to perform some action on all items in that collection
  4. Using the suggested queries all 3 variants are included in the results, which is certainly not correct

Also, the query in this thread example uses “OR” logic to fetch 11 collections at once, and the code that was marked as the solution does not do that, it fetches just one collection’s variants.

Hi @Chris_Geelhoed,

I’ll respond to the various points you raised individually for clarity:

My query is only using using first:1 in the product variant connector as an example to quickly and simply show the behaviour, you can alter this so that any of the connectors in the query requests up to 250 resources per call. You can also paginate on any nested connector as well.

For example, lets say I have 1 collection, with 5 products, with 10 variants each.

I can make a single call with collections(first:1), products(first:1), and variants(first:1)

Using the hasNext field on the edge, if the variants has more than just 1, I can paginate on that connector individually as needed, as well as on any other connector inside of the query.

We also need to consider the product edges. If we try to fetch 250 products with 250 variants, the query cost will be too high to run this query practically. Not to mention, we can’t get a clean 250 item pagination chunk. We could fetch like 15 (sqrt of 250) products with the first 15 variants and manage the cursor of both the inner and outer edges to achieve the same thing we did before, but now our complexity has gone up and our performance has gone down.

You are absolutely correct, and we do not recommend making queries with this many resources retreived, the 250 value is the MAXIUM, not the recommended value, and when you start requesting larger and larger amounts of data per call the more likely the call is going to timeout and return an error.

Also, the query in this thread example uses “OR” logic to fetch 11 collections at once, and the code that was marked as the solution does not do that, it fetches just one collection’s variants.

Again, I do understand this, and my example query was requesting a single collection just for ease of explanation, everything I said still applies if you increase the amount of collections you are requesting.

That all said, if you are concerned about the rate limits for queries such as these, we do have the Bulk Operation Queries that you can use to request large amounts of data asynchronously, so you don’t need to worry about rate limits, or the queries timing out due to requesting too much data at once.

I am going to leave this thread as solved, as again, the issue is a known issue that our developers are aware of and looking into further, and if you have any further questions on this topic, I’d like to ask that you reply in the original thread please.