I’m building a discount Function on cart.lines.discounts.generate.run (API 2026-04, public app). I want product.inCollections(ids: $rulesProductCollections) where $rulesProductCollections is populated at runtime from a shop metafield the merchant configures through my app. Every configuration I’ve tried either fails CLI deploy or makes the binding silently no-op. Looking for someone who has this working in production and can tell me the actual right syntax.
WHAT I’VE TRIED
Form A (deploys, binding always returns null):
[[extensions]]
type = "function"
[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/run.graphql"
export = "run"
[extensions.input.variables]
namespace = "$app:custom_discounts"
key = "rules_product_collections"
GraphQL:
query RunInput($rulesProductCollections: [ID!]!) {
cart { lines { merchandise { ... on ProductVariant { product {
inCollections(ids: $rulesProductCollections) { collectionId isMember }
}}}}}
}
Shop metafield (type json, namespace $app:custom_discounts, key rules_product_collections). I tried two value shapes:
- Bare array: [“gid://shopify/Collection/359951696026”]
- Object with matching key: {“rulesProductCollections”:[“gid://shopify/Collection/359951696026”]}
Both deploy fine. Both produce the same runtime error on every checkout:
Variable $rulesProductCollections of type [ID!]! was provided invalid value
extensions: { code: INVALID_VARIABLE, value: null,
problems: [{ path: [], explanation: "Expected value to not be null" }] }
The metafield genuinely exists with whichever value I set — I read it directly in the same input_query via shop.metafield(namespace, key) { value } and see the JSON intact at runtime. The binding is just always returning null.
Form B (rejected by CLI):
[[extensions.targeting]]
target = "cart.lines.discounts.generate.run"
input_query = "src/run.graphql"
export = "run"
[extensions.targeting.input.variables]
namespace = "$app:custom_discounts"
key = "rules_product_collections"
npx shopify app deploy rejects this with:
Validation errors
- input.variables: Variable definitions are missing. Ensure you have defined them
in your extension configuration and that you are using a supported CLI version.
See documentation for details: https://shopify.dev/api/functions/input-query-variables
I also tried the subtable form [extensions.targeting.input.variables.rulesProductCollections] — same rejection.
The docs URL the error points at returns a vague page that doesn’t show a complete working example for cart.lines.discounts.generate.run. Shopify’s AI assistant gave me three “fixes” that turned out either deploy-breaking or runtime-breaking.
WHAT I’D LOVE TO KNOW FROM SOMEONE WHO’S DONE THIS
- Which @shopify/cli version do I need for Form B (per-target placement)
to actually deploy on this target? - With Form A (extension-scope placement) — is the binding meant to work
at all, and if so, what shape does the metafield value have to be? - Does the GraphQL variable name need to match the metafield key
(snake_case → camelCase auto-conversion, or literal match)? - If [extensions.input.variables] truly doesn’t work for a shop metafield
on cart.lines.discounts.generate.run, what’s the canonical Shopify
pattern for dynamic collection-based product discounts on this target?
I’ll fall back to expanding collections to product IDs at save time
plus a collections/update webhook — but I’d rather use input-variable
binding if it’s supposed to work.
If you have a working shopify.extension.toml + run.graphql + metafield value triple for this target, please paste it. CLI version too if you remember it. That single example would save the next person hitting this several days of guessing.
Thanks.