You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Bug]: 500 on POST /admin/price-lists/:id/prices/batch when updating a plain currency price — admin UI sends empty rules {} (regression in 2.17.2, PR #15258) #15927
macOS 26 (Darwin 27.0) — also reproduced on Linux (Docker) in production
Browser name
Microsoft Edge (irrelevant — reproducible with plain cURL, see below)
What happended?
After upgrading to 2.17.2, editing the amount of an existing price list price in the
admin dashboard always fails with a 500. Creating the price works; only updating an
already-saved plain (currency-only, no region/quantity rules) price fails.
Root cause chain (traced in the installed 2.17.2 sources):
Since PR Feat/quantity pricing admin #15258 ("Tiered Pricing for Price List Prices", shipped in 2.17.2), the
dashboard's edit form always attaches a rules object to every updated price —
for a plain currency price it is an EMPTY object {}.
See comparePrices in packages/admin/dashboard/src/routes/price-lists/common/utils.ts
(in the published bundle: @medusajs/dashboard/dist/chunk-DO2WMVM5.mjs):
In <= 2.17.1 this was rules: regionId ? { region_id } : undefined.
In @medusajs/pricing, PricingModuleService.normalizePrices() only strips the rules key from the upsert entry when isPresent(price.rules) is true — and isPresent({}) returns FALSE, so for an empty object the stray rules key
SURVIVES on the entity data:
const hasRulesInput = isPresent(price.rules)
if (hasRulesInput) {
entry.price_rules = rules
entry.rules_count = rules.length
delete entry.rules // <- never reached for rules: {}
}
upsertWithReplace(pricesToUpsert, { relations: ["price_rules"] }) passes the
entry to MikroORM. Existing rows take the nativeUpdateMany path, which chokes
on the unknown rules property:
TypeError: Cannot read properties of undefined (reading 'fieldNames')
at PostgreSqlDriver.nativeUpdateMany (@mikro-orm/knex/AbstractSqlDriver.js:634:18)
at MikroOrmAbstractBaseRepository_.upsertMany_ (@medusajs/utils/src/dal/mikro-orm/mikro-orm-repository.ts:1408:16)
at async MikroOrmAbstractBaseRepository_.upsertWithReplace (@medusajs/utils/src/dal/mikro-orm/mikro-orm-repository.ts:701:11)
...
[update-price-list-prices -> update-price-list-prices (invoke)]
[batch-price-list-prices -> update-price-list-prices-as-step (invoke)]
New prices go through the insert path (which maps only known columns), which is
why CREATE succeeds and only UPDATE fails.
Consistent with the above:
update WITHOUT the rules key -> 200 OK
update with rules: {} -> 500 (this bug; what the admin UI sends)
update with rules: {"region_id": "..."} -> 200 OK (non-empty rules are converted properly)
Expected behavior
Updating the amount of an existing price list price (via the admin dashboard edit
form, or via POST /admin/price-lists/:id/prices/batch with rules: {} in an update
entry) should return 200 and update the price — same as in <= 2.17.1. An empty rules object should be treated the same as an absent/undefined one.
TypeError: Cannot read properties of undefined (reading 'fieldNames')
at PostgreSqlDriver.nativeUpdateMany (@mikro-orm/knex/AbstractSqlDriver.js:634:18)
The admin dashboard shows a generic "An unknown error occurred." toast, so price
list prices are effectively not editable from the UI at all (plain currency prices).
Link to reproduction repo
Reproducible on a vanilla create-medusa-app@latest (2.17.2) install with no custom code — two cURL calls below are a complete reproduction, so I hope a repo is not necessary
Package.json file
{ "name": "medusa-backend", "version": "0.0.1", "dependencies": { "@medusajs/admin-sdk": "2.17.2", "@medusajs/cli": "2.17.2", "@medusajs/framework": "2.17.2", "@medusajs/medusa": "2.17.2", "@google/genai": "^1.34.0", "@lambdacurry/medusa-product-reviews": "1.4.0", "@perseidesjs/notification-nodemailer": "^2.0.0", "@rokmohar/medusa-plugin-meilisearch": "1.4.3", "@variablevic/google-analytics-medusa": "^0.1.1", "fast-xml-parser": "^5.3.3", "medusa-inpost-fulfillment": "^0.4.0", "nodemailer": "^7.0.12", "sanitize-html": "^2.17.5", "slugify": "^1.6.6" }, "devDependencies": { "@medusajs/test-utils": "2.17.2", "@swc/core": "^1.7.28", "jest": "^29.7.0", "ts-node": "^10.9.2", "typescript": "^5" } }Node.js version
v22.22.3
Database and its version
PostgreSQL 18.0
Operating system name and version
macOS 26 (Darwin 27.0) — also reproduced on Linux (Docker) in production
Browser name
Microsoft Edge (irrelevant — reproducible with plain cURL, see below)
What happended?
After upgrading to 2.17.2, editing the amount of an existing price list price in the
admin dashboard always fails with a 500. Creating the price works; only updating an
already-saved plain (currency-only, no region/quantity rules) price fails.
Root cause chain (traced in the installed 2.17.2 sources):
Since PR Feat/quantity pricing admin #15258 ("Tiered Pricing for Price List Prices", shipped in 2.17.2), the
dashboard's edit form always attaches a
rulesobject to every updated price —for a plain currency price it is an EMPTY object
{}.See
comparePricesinpackages/admin/dashboard/src/routes/price-lists/common/utils.ts(in the published bundle:
@medusajs/dashboard/dist/chunk-DO2WMVM5.mjs):pricesToUpdate.push({
id, variant_id, currency_code, amount,
rules: {
...(newPrice.regionId ? { region_id: newPrice.regionId } : {}),
...
}, // <- {} for a plain currency price
})
In <= 2.17.1 this was
rules: regionId ? { region_id } : undefined.In
@medusajs/pricing,PricingModuleService.normalizePrices()only strips theruleskey from the upsert entry whenisPresent(price.rules)is true — andisPresent({})returns FALSE, so for an empty object the strayruleskeySURVIVES on the entity data:
const hasRulesInput = isPresent(price.rules)
if (hasRulesInput) {
entry.price_rules = rules
entry.rules_count = rules.length
delete entry.rules // <- never reached for rules: {}
}
upsertWithReplace(pricesToUpsert, { relations: ["price_rules"] })passes theentry to MikroORM. Existing rows take the
nativeUpdateManypath, which chokeson the unknown
rulesproperty:TypeError: Cannot read properties of undefined (reading 'fieldNames')
at PostgreSqlDriver.nativeUpdateMany (@mikro-orm/knex/AbstractSqlDriver.js:634:18)
at MikroOrmAbstractBaseRepository_.upsertMany_ (@medusajs/utils/src/dal/mikro-orm/mikro-orm-repository.ts:1408:16)
at async MikroOrmAbstractBaseRepository_.upsertWithReplace (@medusajs/utils/src/dal/mikro-orm/mikro-orm-repository.ts:701:11)
...
[update-price-list-prices -> update-price-list-prices (invoke)]
[batch-price-list-prices -> update-price-list-prices-as-step (invoke)]
New prices go through the insert path (which maps only known columns), which is
why CREATE succeeds and only UPDATE fails.
Consistent with the above:
ruleskey -> 200 OKrules: {}-> 500 (this bug; what the admin UI sends)rules: {"region_id": "..."}-> 200 OK (non-empty rules are converted properly)Expected behavior
Updating the amount of an existing price list price (via the admin dashboard edit
form, or via POST /admin/price-lists/:id/prices/batch with
rules: {}in an updateentry) should return 200 and update the price — same as in <= 2.17.1. An empty
rulesobject should be treated the same as an absent/undefined one.Actual behavior
HTTP 500 with body:
{"code":"unknown_error","type":"unknown_error","message":"An unknown error occurred."}
and the following server-side error:
TypeError: Cannot read properties of undefined (reading 'fieldNames')
at PostgreSqlDriver.nativeUpdateMany (@mikro-orm/knex/AbstractSqlDriver.js:634:18)
The admin dashboard shows a generic "An unknown error occurred." toast, so price
list prices are effectively not editable from the UI at all (plain currency prices).
Link to reproduction repo
Reproducible on a vanilla
create-medusa-app@latest(2.17.2) install with no custom code — two cURL calls below are a complete reproduction, so I hope a repo is not necessary