Unable to update ProductTaxonomyID using GraphQL from Python

Topic summary

A developer is encountering an error when attempting to update a product’s taxonomy using Shopify’s GraphQL API from Python. The error message states: “Field ‘productTaxonomyNodeId’ doesn’t exist on type ‘ProductCategory’”

The Issue:

  • The mutation structure and input fields appear correct according to documentation
  • The productUpdate mutation is being used with proper GID formatting
  • Error occurs despite following the documented productCategory structure

The Solution (provided by ShopifyDevSup):
The problem lies in the response fields being requested, not the input:

  • Input fields are correct: productCategory: { productTaxonomyNodeId: "gid://..." }
  • Response fields should request productTaxonomyNode { id } instead of productTaxonomyNodeId

Corrected Query Structure:

product {
  productCategory {
    productTaxonomyNode {
      id
    }
  }
}

The developer needs to modify their mutation’s return fields to match the actual GraphQL schema structure for querying the updated taxonomy data.

Summarized with AI on November 10. AI used: claude-sonnet-4-5-20250929.

Hi, everyone.

I am following GraphQL Documentation and trying to update the ProductTaxonomy for my products. I have got my Product ID and also the Product Taxonomy ID and I have created the below function,

def update_product_taxonomy(product_gid, product_taxonomy_node_id):

        mutation = """
        mutation productUpdate($input: ProductInput!) {
          productUpdate(input: $input) {
            product {
              id
              productCategory {
                productTaxonomyNodeId
              }
            }
            userErrors {
              field
              message
            }
          }
        }

        """

        variables = {
            "input": {
                "id": f"gid://shopify/Product/{product_gid}",
                "productCategory": {
                    "productTaxonomyNodeId": f"gid://shopify/ProductTaxonomyNode/{int(product_taxonomy_node_id)}"
                }
            }
        }

        headers = {
            "Content-Type": "application/json",
            "X-Shopify-Access-Token": token
        }

        response = graphql_request(GRAPHQL_URL, headers, mutation, variables)
        if response['success']:
            logging.info(f"Product {product_gid} taxonomy updated successfully to {product_taxonomy_node_id}.")
            product_taxonomy_logs.append(f"Product {product_gid} taxonomy updated successfully to {product_taxonomy_node_id}.")
            return True
        else:
            logging.error(f"Failed to update product {product_gid} taxonomy, errors: {response.get('errors', [])}")
            product_taxonomy_logs.append(f"Failed to update product {product_gid} taxonomy, errors: {response.get('errors', [])}")
            return False

I also have another generic function for GraphQL Requests, which I have given below,

def graphql_request(url, headers, query, variables, max_retries=2, retry_delay=2):
        attempt = 0
        while attempt < max_retries:
            try:
                response = requests.post(url, headers=headers, json={'query': query, 'variables': variables})
                print("Request sent:", {'query': query, 'variables': variables})  # Log the request
                if response.status_code == 200:
                    try:
                        json_data = response.json()
                        print("Response received:", json_data)  # Log the response
                        if 'errors' in json_data:  # Handle GraphQL errors
                            error_message = "; ".join([error['message'] for error in json_data['errors']])
                            logging.error(f"GraphQL error on attempt {attempt}: {error_message}")
                            # return {'success': False, 'errors': json_data['errors']}
                        else:
                            return {'success': True, 'data': json_data}
                    except json.JSONDecodeError as e:
                        logging.error(f"Failed to parse JSON response on attempt {attempt}. Error: {e}")
                else:
                    logging.error(f"Received HTTP {response.status_code}, retrying... Attempt: {attempt}")
            except requests.exceptions.RequestException as e:
                logging.error(f"Request failed on attempt {attempt}. Error: {e}")

            attempt += 1
            time.sleep(retry_delay * (2 ** attempt))  # Exponential backoff

        logging.error("Max retries exceeded.")
        return {'success': False, 'errors': ['Max retries exceeded.']}

I am quite certain that the mutation and structure I am following is according to what is provided by productUpdate mutation but I am still getting an error:

Field ‘productTaxonomyNodeId’ doesn’t exist on type ‘ProductCategory’

Can anyone help in this regard? I am not sure what I am doing wrong.

Please find below my Request (that is being sent to API) and also the complete response I am getting.

Request sent

Request sent: {'query': '\n        mutation productUpdate($input: ProductInput!) {\n          productUpdate(input: $input) {\n            product {\n              id\n              productCategory {\n                productTaxonomyNodeId\n              }\n            }\n            userErrors {\n              field\n              message\n            }\n          }\n        }\n\n\n        ', 'variables': {'input': {'id': 'gid://shopify/Product/9187042787610', 'productCategory': {'productTaxonomyNodeId': 'gid://shopify/ProductTaxonomyNode/3621'}}}}

Response Received,

Response received: {'errors': [{'message': "Field 'productTaxonomyNodeId' doesn't exist on type 'ProductCategory'", 'locations': [{'line': 7, 'column': 17}], 'path': ['mutation productUpdate', 'productUpdate', 'product', 'productCategory', 'productTaxonomyNodeId'], 'extensions': {'code': 'undefinedField', 'typeName': 'ProductCategory', 'fieldName': 'productTaxonomyNodeId'}}]}

Hey @hassanashas ,

Thanks for sharing the clear example. It really helps.

Comparing your request to our documentation, the issue is in the productCategory field that you’re requesting to be returned.

The input fields are correct,

“productCategory”: {> “productTaxonomyNodeId”: “gid://shopify/ProductTaxonomyNode/3621”> }

The response fields are actually slightly different.

Changing your request to the following should resolve the error you are getting:

productCategory {> productTaxonomyNode {> id> }

Here’s an example of a simplified mutation to demonstrate:

mutation ProductUpdate {> productUpdate(> input: {> id: “gid://shopify/Product/9187042787610”> productCategory: {> productTaxonomyNodeId: “gid://shopify/ProductTaxonomyNode/3621”> }> }> ) {> product {> productCategory {> productTaxonomyNode {> id> }> }> }> }> }

Hope that helps

  • Kyle G.