Product Discount Function - CartLine targets bug

Topic summary

Core Issue:
Developers are encountering an error when attempting to use cartLine targets in Shopify product discount functions. Despite official documentation indicating that CartLineTarget is valid alongside ProductVariantTarget, the system rejects it with the error: “Expected one of valid values: productVariant. Got: cartLine.”

Attempted Solutions:

  • Updating to API version 2024-07 and regenerating TypeScript types via npm run shopify app function typegen did not resolve the issue
  • The error persists across multiple API versions (2024-04 and 2024-07)
  • Users report that DiscountApplicationStrategy.All also fails to work properly, preventing multiple discounts from being applied

Working Solution Found:
One participant discovered a workaround by referencing older documentation from a GitHub repository (Shopify function-examples). Key insight: Setting discountApplicationStrategy to “All” (rather than DiscountApplicationStrategy.All) allows multiple cart lines to be discounted successfully.

Current Status:
The discussion remains open with participants reviewing the shared solution. The discrepancy between official documentation and actual API behavior suggests a potential documentation error or API limitation.

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

We’re currently working on shopify product discounts where we’re fetching the discount value via line item property and utilizing it to provide fixedAmount off on the line item with selling plan. As per the given documentation, we’ve referred that we could also pass theCartLineTarget along with ProductVariantTarget within the targets as part response from product discount functions. Ref: https://shopify.dev/docs/api/functions/reference/product-discounts/graphql/common-objects/target

Currently we’re trying to replicate the same behaviour as mentioned here within output_2.json of this example where discounts are applied on cartLines rather than productVariants:

https://shopify.dev/docs/api/functions/reference/product-discounts/graphql#functionrunresult

Although the cartLine is accepted as per official documentation we’re getting the below error within the partner logs stating:

"Expected one of valid values: productVariant. Got: cartLine"

Adding the relevant references below -

Output (STDOUT)

{
  "discountApplicationStrategy": "ALL",
  "discounts": [
    {
      "targets": [
        {
          "cartLine": {
            "id": "gid://shopify/CartLine/0"
          }
        }
      ],
      "message": "11 off plus additional discount based on product type value",
      "value": {
        "fixedAmount": {
          "amount": 11
        }
      }
    },
    {
      "targets": [
        {
          "cartLine": {
            "id": "gid://shopify/CartLine/1"
          }
        }
      ],
      "message": "15 off plus additional discount based on product type value",
      "value": {
        "fixedAmount": {
          "amount": 15
        }
      }
    },
    {
      "targets": [
        {
          "cartLine": {
            "id": "gid://shopify/CartLine/2"
          }
        }
      ],
      "message": "18 off plus additional discount based on product type value",
      "value": {
        "fixedAmount": {
          "amount": 18
        }
      }
    }
  ]
}

Error Message

[
  {
    "path": [
      "discounts",
      0,
      "targets",
      0
    ],
    "explanation": "Expected one of valid values: productVariant. Got: cartLine"
  },
  {
    "path": [
      "discounts",
      1,
      "targets",
      0
    ],
    "explanation": "Expected one of valid values: productVariant. Got: cartLine"
  },
  {
    "path": [
      "discounts",
      2,
      "targets",
      0
    ],
    "explanation": "Expected one of valid values: productVariant. Got: cartLine"
  }
]

run.graphql

query RunInput {
  cart {
    lines {
      id
      quantity
      attribute (key: "Product_Type") {
        key
        value
      }
      sellingPlanAllocation{
        priceAdjustments {
          perDeliveryPrice {
            amount
          }
          price {
            amount
          }
        }
        sellingPlan {
          id
          name
          recurringDeliveries
        }
      }
      merchandise {
        __typename
        ... on ProductVariant {
          id
        }
      }
    }
  }
}
 

run.js

// @ts-check
import { DiscountApplicationStrategy } from "../generated/api";
/**
 * @typedef {import("../generated/api").RunInput} RunInput
 * @typedef {import("../generated/api").FunctionRunResult} FunctionRunResult
 */
 
const discount = 25;
const uniqueGiftCard = 2;
 
/**
 * @type {FunctionRunResult}
 */
const EMPTY_DISCOUNT = {
  discountApplicationStrategy: DiscountApplicationStrategy.All,
  discounts: []
};

/**
 * @param {RunInput} input
 * @returns {FunctionRunResult}
 */
export function run(input) {
 
  console.error("FUNCTION IS RUNNING");
 
  const targets = input.cart.lines
    .filter(line => line.quantity >= 1 && line.sellingPlanAllocation && line.sellingPlanAllocation.priceAdjustments.length && line.sellingPlanAllocation.priceAdjustments[0] && line.sellingPlanAllocation.priceAdjustments[0].price.amount && line.attribute && line.attribute.value && line.merchandise.__typename === 'ProductVariant')
    .map(line => {
      return {
        productVariant: {
          id: line.merchandise.id
        },
        cartLine: {
          id: line.id
        },
        productTypeValue: parseFloat(line.attribute.value) // Assuming attribute value is parsable to float
      }
    });

  const discounts = targets.map(target => ({
    targets: [{ cartLine: target.cartLine }],
    message: (target.productTypeValue + ' off plus additional discount based on product type value'),
    value: {
      fixedAmount: {
        amount: target.productTypeValue // Dynamic amount based on product type
      }
    }
  }));

  /**
   * @type {FunctionRunResult}
   */
  const ACTUAL_DISCOUNT = {
    discountApplicationStrategy: DiscountApplicationStrategy.All,
    discounts: discounts
  };

  return targets.length === 0 ? EMPTY_DISCOUNT : ACTUAL_DISCOUNT;
};

Also note: found the error in code stating - Type ‘{ cartLine: { id: string; }; }’ is not assignable to type ‘Target’.
Property ‘productVariant’ is missing in type ‘{ cartLine: { id: string; }; }’ but required in type ‘Target’.

Are you using API version 2024-07? If not, you need to update your shopify.function.extension.toml (or shopify.extension.toml, depending on when you created your function).

This does not fix the issue.

Well, what else have you tried? Have you run npm run shopify app function typegen? You probably need to regenerate TypeScript files based on the schema…

Yes, that seems to work as I get " GraphQL types generated successfully." However, when viewing the error logs I see

[  {
    "path": [
      "discounts",
      0,
      "targets",
      0
    ],
    "explanation": "Expected one of valid values: productVariant. Got: cartLine"
  }
]

I have the same problem. Supposedly, I’m using the 2024-04 API, and I also tried the 2024-07 version, but DiscountApplicationStrategy.All doesn’t work. I can’t apply multiple discounts. Any help, any suggestions?
Thanks, a lot!

I searched for everything it seems like, and was able to find someone that was using older documentation. I tried it and it worked for me. Here is the GitHub repo: https://github.com/Shopify/function-examples/tree/main/sample-apps/discounts/extensions/product-discount-js/src.

Hope this helps!

Setting discountApplicationStrategy to “All” will allow for multiple cart lines to be discounted.

discountApplicationStrategy: DiscountApplicationStrategy.All

1 Like

Thank you so much for taking the time to look into this and respond to me. I will review what you sent me. Thanks again.