#16822·medusa

[Bug]: Customer-group price lists never apply — rules are written as `customer_group_id` but matched as `customer.groups.id`

Author: Jovial1989Created Sep 15, 2026Updated Sep 15, 2026
Labelstype: bugrequires-team

Bug report

A price list whose rule targets a customer group is silently ignored during price calculation. Customers in the group keep paying the default price — no error, no warning.

The cause is an attribute-name mismatch between the two halves of the feature:

attribute
written by the admin dashboard, POST /admin/price-lists, and createPriceListsWorkflow customer_group_id
matched by PricingRepository.calculatePrices after flattenObjectToKeyValuePairs flattens the pricing context customer.groups.id

price_list_rule.attribute is compared verbatim against the flattened context key (plr.attribute = ? in packages/modules/pricing/src/repositories/pricing.ts), so the two never meet.

Minimal reproduction

The context built by the store product route (packages/medusa/src/api/utils/middlewares/products/set-pricing-context.ts) flattens like this:

typescript
flattenObjectToKeyValuePairs({
  region_id: "reg_1",
  customer: { groups: [{ id: "cusgroup_1" }] },
})
// => { region_id: "reg_1", "customer.groups.id": ["cusgroup_1"] }
//                          ^ not "customer_group_id"

End to end against a running server:

  1. Create a customer group and a customer in it.
  2. Create a variant priced at 1000.
  3. POST /admin/price-lists with { "type": "override", "status": "active", "rules": { "customer_group_id": ["<groupId>"] }, "prices": [{ "variant_id": "<id>", "currency_code": "usd", "amount": 780 }] }
  4. As that customer: GET /store/products?region_id=…&fields=*variants.calculated_price

Expected: calculated_amount 780, is_calculated_price_price_list true. Actual: calculated_amount 1000, is_calculated_price_price_list false.

Changing only the rule attribute fixes it:

sql
UPDATE price_list_rule SET attribute = 'customer.groups.id' WHERE attribute = 'customer_group_id';

After that the same request returns 780.

The same failure happens through the cart — line items are created at the default price for customers in the group.

Two things that make this hard to notice:

  • The admin dashboard still renders the price list correctly ("Customer groups · Wholesale"), because the display path resolves groups from the rule value regardless of the attribute name.
  • GET /admin/price-lists echoes back whatever attribute is stored, so the API response looks consistent either way.

Note that customer.groups.id is the attribute the rest of v2 already uses for this concept — see rule-attributes-map.ts for promotions, and the customer.groups.id field lists in the cart and order workflows.

System information

Medusa version (including plugins): @medusajs/medusa 2.21.0, @medusajs/pricing 2.21.0, @medusajs/core-flows 2.21.0 Node.js version: 20.20.2 Database: PostgreSQL 15.19 Operating system: macOS (Darwin 25.4.0) Browser (if relevant): n/a