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

  1. Fetch the option's current rules first and only include IDs present in updateShippingOptions(id).rules
  2. For new rules, omit the id field so they are created instead of matched
  3. 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

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


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/e00cd503259138fb. Report an issue: GitHub.