medusajs/medusa · error · MedusaError

Invalid rule attribute - ${ruleAttributeId}

Error message

Invalid rule attribute - ${ruleAttributeId}

What it means

Thrown by validateRuleAttribute when the supplied rule attribute id is not in the list of valid attributes for the given rule type. The valid set is derived from the promotion rules context (e.g. rule attributes for a certain application method target type), and the requested attribute must be one of them.

Source

Thrown at packages/medusa/src/api/admin/promotions/utils/validate-rule-attribute.ts:35

  const {
    promotionType,
    ruleType,
    ruleAttributeId,
    applicationMethodType,
    applicationMethodTargetType,
  } = attributes

  const ruleAttributes =
    getRuleAttributesMap({
      promotionType,
      applicationMethodType,
      applicationMethodTargetType,
    })[ruleType] || []

  const ruleAttribute = ruleAttributes.find((obj) => obj.id === ruleAttributeId)

  if (!ruleAttribute) {
    throw new MedusaError(
      MedusaError.Types.INVALID_DATA,
      `Invalid rule attribute - ${ruleAttributeId}`
    )
  }
}

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Fetch the current valid attributes for the rule type first and restrict the UI/options to that list
  2. Send the attribute's id exactly as returned by the attributes listing endpoint
  3. After upgrading Medusa, re-sync any cached rule attribute lists

Example fix

// before
GET /admin/promotions/rule-attributes?rule_type=rules&rule_attribute_id=region_id_old

// after
// fetch valid attributes first
const attrs = await getRuleAttributes(ruleType, applicationMethodTargetType)
if (!attrs.some((a) => a.id === ruleAttributeId)) {
  throw new Error(`Pick one of: ${attrs.map((a) => a.id).join(", ")}`)
}
Defensive patterns

Strategy: validation

Validate before calling

const attrs = await getRuleAttributes(ruleType, applicationMethodTargetType)
const valid = new Set(attrs.map((a) => a.id))
if (!valid.has(ruleAttributeId)) {
  throw new Error(`rule_attribute must be one of: ${[...valid].join(", ")}`)
}

Type guard

const isValidRuleAttribute = (id: string, attrs: { id: string }[]) =>
  attrs.some((a) => a.id === id)

Try / catch

try {
  await validateRuleAttribute(...)
} catch (e: any) {
  if (e.statusCode === 400 && /Invalid rule attribute/.test(e.message)) refreshAttributes()
  else throw e
}

Prevention

When it happens

Trigger: Calling the promotion rule validation endpoints (GET rule attributes flows) with a rule_attribute id that does not exist for the resolved rule_type, or a rule attribute belonging to a different target type (items/shipping_methods/etc.).

Common situations: Custom admin UIs offering stale attribute lists after a Medusa upgrade changed available attributes, passing attribute labels instead of ids, or hardcoding attribute ids that no longer exist.

Related errors


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