Possible bug: querying products tagged with 'trainers' returns products tagged with 'not-trainers'

I have the following query:

query GetProductsTagged {
          products(query: "status:ACTIVE,tag:Trainers", first: 200) {
        
                nodes {
                
                  id
                  title
                  herring_shoe_id: metafield(namespace: "custom", key: "herring_shoe_id") {
                  
                      value
                      
                  }
                 
            }
            
            pageInfo {
              startCursor
              endCursor
            }
            
          }
          
        }

I have 1351 products tagged with the tag ā€˜not-trainers’, which is a utility tag we use to help craft collections of products that we don’t want to see trainers in. This is necessary because of Shopify’s limited smart collection functionality: we can’t specify a NOT condition for tags in the rules, so this is the workaround we came up with.

I have zero products tagged with the tag ā€˜Trainers’.

The above query, which I will remind us all has the query ā€œstatus:ACTIVE,tag:Trainersā€ returns…

Yes, you guessed it, it returns the 1351 products with the ā€˜not-trainers’ tag.

So then I thought, OK, Shopify must do this search based on the tag term being like a tag, so I repeated the query with the term ā€˜rainer’:

products(query: ā€œstatus:ACTIVE,tag:rainerā€, first: 200) {

…and got zero results.

When I wrap the tag term in quotes, like some other examples in the documentation for the products query, like this: products(query: ā€œstatus:ACTIVE,tag:ā€˜Trainersā€™ā€, first: 200) {

The results are the same. 1351 for ā€˜Trainers’, again returning the ā€˜not-trainers’ products, and zero for ā€˜rainer’.

If anyone can shed some light on what is going on here, that would be amazing.

In the meantime I now have to rewrite this code to just get all products, get each product’s tags, and then check to see if the tag I’m interested in is one of them. This is bonkers.

Many thanks,

G

PS - wait, did I just do a (minor) inadvertant injection attack?

Edit: noticed the same problem with the productsCount query:

query {
  productsCount(query: "status:ACTIVE,tag:Trainers",limit: null) {
    count
  }
}

returns a count of 1351.

1 Like

Hey @dartacus! I initially thought this might be a query syntax issue - you’re using "status:ACTIVE,tag:Trainers" when the search syntax grammar requires terms to be separated by spaces or explicit connectives like AND/OR (not commas).

However, when I tested with the documented syntax ("status:ACTIVE tag:Trainers"), the issue still occurs. I tested on my dev store with only not-trainers products (no Trainers products at all), and searching for tag:Trainers still returned the not-trainers products. This happens whether you use quotes for phrase matching or not.

I came across a workaround though; switching from hyphens to underscores. When I tested tag:Trainers, it matched exactly and didn’t return any products with the not-trainers tag. So you’d need to update your products to use not_trainers instead of not-trainers, which I know is far from ideal.

I’m going to raise this with our API platform team to understand if this tag matching behavior is expected. Do you have any x-request-ids from your API calls I can include when I reach out to them? That would help them investigate your specific requests in case my replication isn’t exactly right

I don’t but I can run them again and get them, I have unit tests set up for this.

OK, with quotes: ef7b7798-be69-415f-a583-16d07453292b-1763569077

Without quotes: b5539b47-32c4-4ce8-a26b-5d941fe8ceeb-1763569230

Hope that helps,

G

Ideal, I’ll have the products team take a look at this (they own product-related api queries) and get back to you once I have more info to share. Thanks for sharing those!

Thanks for the hint on not separating queries with commas, too, don’t know where I picked that up, likely trial and error. Will use AND from now on.

G

1 Like

Hey @dartacus !

I heard back from our products team about this. Turns out this is expected behavior, though I agree it’s not intuitive.

Tags with hyphens get tokenized during search - so not-trainers is split into two tokens: not and trainers. When you search for tag:Trainers, it matches any tag containing the word ā€œtrainersā€, which includes your not-trainers tags. This is how the search syntax works for tokenized fields - the : operator finds the term anywhere in the field.

The good news is there are a couple of workarounds:

Option 1 (as I found during testing): Use underscores instead of hyphens in your tags (e.g., not_trainers instead of not-trainers). Underscores don’t act as tokenization delimiters, so tag:Trainers won’t match not_trainers.

Option 2 (Suggested by the Products team): Use negative filtering in your query:

query GetProductsTagged {
  products(query: "status:ACTIVE tag_not:not AND tag:trainers", first: 200) {
    nodes {
      id
      title
      tags
    }
  }
}

This tells the API ā€œgive me products tagged with trainers but NOT tagged with notā€.

I’ve raised this with the products team to see if we can either change the behavior or document this limitation more clearly. They’ve created an issue to track it internally.

Thanks for flagging this, I hadn’t come across it before personally!

Thanks Donal, appreciate you letting me know that it’s been flagged internally. (I’ll do a reworking of all our tags using option 2 so as to be able to use option 1).

Cheers,

G

1 Like