medusajs/medusa · error · MedusaError
The following rules does not exists: ${Array.from(nonAlready
Error message
The following rules does not exists: ${Array.from(nonAlreadyExistingRules).join(", ")} on shipping option ${shippingOptionUpdateData.id} What it means
Thrown when updating a shipping option's rules with IDs that do not belong to (or do not exist on) that shipping option. The module computes a set difference between the rule IDs you passed and the option's actual rules; any extra ID is rejected as NOT_FOUND.
Source
Thrown at packages/modules/fulfillment/src/services/fulfillment-module-service.ts:2137
shippingOptionUpdateData: FulfillmentTypes.UpdateShippingOptionDTO
) {
if (!shippingOptionUpdateData.rules) {
return
}
const existingRules = shippingOption.rules
const rulesSet = new Set(existingRules.map((r) => r.id))
// Only validate the rules that have an id to validate that they really exists in the shipping option
const expectedRuleSet = new Set(
shippingOptionUpdateData.rules
.map((r) => "id" in r && r.id)
.filter((id): id is string => !!id)
)
const nonAlreadyExistingRules = getSetDifference(expectedRuleSet, rulesSet)
if (nonAlreadyExistingRules.size) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`The following rules does not exists: ${Array.from(
nonAlreadyExistingRules
).join(", ")} on shipping option ${shippingOptionUpdateData.id}`
)
}
}
protected static validateGeoZones(
geoZones: (
| (Partial<FulfillmentTypes.CreateGeoZoneDTO> & { type: string })
| (Partial<FulfillmentTypes.UpdateGeoZoneDTO> & { type: string })
)[]
) {
const requirePropForType = {
country: ["country_code"],
province: ["country_code", "province_code"],
city: ["country_code", "province_code", "city"],View on GitHub (pinned to 5e06e544a2)
Solutions
- Fetch the option's current rules first and only include IDs present in updateShippingOptions(id).rules
- For new rules, omit the id field so they are created instead of matched
- Re-fetch fresh rule IDs before each update (avoid caching them in client state)
Example fix
// before
await service.updateShippingOptions([{ id: soId, rules: [{ id: 'sor_stale', operator: 'eq', attribute: 'iso', value: 'dk' }] }])
// after
const [option] = await service.listShippingOptions({ id: soId })
const validIds = new Set(option.rules.map((r) => r.id))
const rules = payload.rules.map((r) => (r.id && !validIds.has(r.id) ? { ...r, id: undefined } : r))
await service.updateShippingOptions([{ id: soId, rules }]) Defensive patterns
Strategy: validation
Validate before calling
const [option] = await fulfillmentService.listShippingOptions({ id: update.id })
const valid = new Set(option.rules.map((r) => r.id))
const safeRules = update.rules.filter((r) => !r.id || valid.has(r.id)) Type guard
const isExistingRuleId = (id: string | undefined, valid: Set<string>): boolean => !id || valid.has(id)
Try / catch
catch (e) { if (/rules does not exist/i.test(e.message)) { /* refetch rules and retry without stale ids */ } } Prevention
- Send rule id only when updating a known rule; omit id to create
- Refetch the option's rules right before editing
When it happens
Trigger: updateShippingOptions with a rules array containing { id: 'sor_xxx' } where that rule ID does not exist on the given shipping option — typo'd IDs, rules deleted by a concurrent update, or IDs copied from another option.
Common situations: UI editing rules where the client sends stale rule IDs; syncing rule sets between environments; concurrent admin edits.
Related errors
- The following shipping options do not exist: ${Array.from(mi
- Service zone with id: ${req.params.zone_id} not found
- Rule must have an attribute, an operator and a value
- Rule attribute must be a string
- Rule operator must be a string
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/e00cd503259138fb.
Report an issue: GitHub.