medusajs/medusa · error · MedusaError
No product ids passed to remove from price list
Error message
No product ids passed to remove from price list
What it means
Thrown by POST /admin/price-lists/:id/products when the body's remove array is empty. The endpoint exists specifically to remove products from a price list, so a request without at least one product id in remove is rejected as INVALID_DATA before any workflow runs.
Source
Thrown at packages/medusa/src/api/admin/price-lists/[id]/products/route.ts:21
import { MedusaError } from "@medusajs/framework/utils"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "@medusajs/framework/http"
import { fetchPriceList, fetchPriceListPriceIdsForProduct } from "../../helpers"
export const POST = async (
req: AuthenticatedMedusaRequest<
HttpTypes.AdminLinkPriceListProducts,
HttpTypes.AdminPriceListParams
>,
res: MedusaResponse<HttpTypes.AdminPriceListResponse>
) => {
const id = req.params.id
const { remove = [] } = req.validatedBody
if (!remove.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"No product ids passed to remove from price list"
)
}
const productPriceIds = await fetchPriceListPriceIdsForProduct(
id,
remove,
req.scope
)
const workflow = batchPriceListPricesWorkflow(req.scope)
await workflow.run({
input: {
data: {
id,
create: [],
update: [],View on GitHub (pinned to 5e06e544a2)
Solutions
- Only call the endpoint when at least one product id is selected; guard client-side on remove.length > 0
- Send the body as { remove: ["prod_..."] } with the remove key
- If you meant to assign products to a price list, use the appropriate product-add endpoint instead
Example fix
// before
await sdk.client.fetch(`/admin/price-lists/${id}/products`, { method: "POST", body: { remove: selectedIds } }) // selectedIds may be []
// after
if (selectedIds.length > 0) {
await sdk.client.fetch(`/admin/price-lists/${id}/products`, { method: "POST", body: { remove: selectedIds } })
} Defensive patterns
Strategy: validation
Validate before calling
const toRemove = selectedIds.filter(Boolean)
if (toRemove.length === 0) return // nothing to do, skip the call
await sdk.client.fetch(`/admin/price-lists/${id}/products`, { method: "POST", body: { remove: toRemove } }) Type guard
const hasRemovals = (b: { remove?: string[] }) => Array.isArray(b.remove) && b.remove.length > 0 Prevention
- Disable submit when no rows are selected
- Validate request bodies with zod: z.object({ remove: z.string().array().min(1) })
- Check payload keys before sending
When it happens
Trigger: Calling the endpoint with { remove: [] } or omitting remove entirely (it defaults to []), or sending ids under the wrong key (e.g. product_ids).
Common situations: Frontends that always call the endpoint even when the user deselected nothing, API consumers confusing this route with the products batch route that also accepts add/list fields, or a serialization bug producing an empty array.
Related errors
- Price list with id: ${id} was not found
- Invite with id: ${id} was not found
- Price list with id: ${id} was not found
- Product category with id: ${req.params.id} was not found
- Product option value with id "${valueId}" was not found for
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/5555727d309938fc.
Report an issue: GitHub.