{"record":{"id":"f7649d0410697b64","repo":"medusajs/medusa","slug":"rule-operator-must-be-a-string","errorCode":null,"errorMessage":"Rule operator must be a string","messagePattern":"Rule operator must be a string","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/fulfillment/src/utils/utils.ts","lineNumber":114,"sourceCode":" * @param rule\n */\nexport function validateRule(rule: Record<string, unknown>): boolean {\n  if (!rule.attribute || !rule.operator || !rule.value) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      \"Rule must have an attribute, an operator and a value\"\n    )\n  }\n\n  if (!isString(rule.attribute)) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      \"Rule attribute must be a string\"\n    )\n  }\n\n  if (!isString(rule.operator)) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      \"Rule operator must be a string\"\n    )\n  }\n\n  if (!availableOperators.includes(rule.operator as RuleOperator)) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      `Rule operator ${\n        rule.operator\n      } is not supported. Must be one of ${availableOperators.join(\", \")}`\n    )\n  }\n\n  if (rule.operator === RuleOperator.IN || rule.operator === RuleOperator.NIN) {\n    if (!Array.isArray(rule.value)) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/fulfillment/src/utils/utils.ts#L96-L132","documentation":"Within validateRule, the rule's operator must be a string. Non-string operators (numbers, objects) throw INVALID_DATA before the supported-operator check runs.","triggerScenarios":"Passing operator as an enum-like numeric code or an object from a query parser (e.g. operator[something]).","commonSituations":"Form encoders producing nested objects; mapping external condition codes directly to operator.","solutions":["Pass operator as one of the string literals ('eq','neq','gt','gte','lt','lte','in','nin')","Normalize input at the API boundary"],"exampleFix":"// before\nrules: [{ attribute: 'iso', operator: 1, value: 'dk' }]\n// after\nrules: [{ attribute: 'iso', operator: 'eq', value: 'dk' }]","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const hasStringOperator = (r: any): boolean => typeof r?.operator === 'string'","tryCatchPattern":null,"preventionTips":["Expose operators as a fixed dropdown of string literals","Parse query-string payloads carefully to avoid nested objects"],"tags":["fulfillment","rules","type-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}