medusajs/medusa · error · MedusaError
Invalid operator: ${operator}
Error message
Invalid operator: ${operator} What it means
Part of Medusa's cross-module query builder that translates filter objects into SQL. Only a fixed set of operators ($eq, $ne, $lt, $gt, $in, $like, $null, etc.) is supported; anything else reaches the switch default and throws INVALID_DATA.
Source
Thrown at packages/core/utils/src/dal/mikro-orm/cross-module-query/filter-sql.ts:388
bindings.push(value as Knex.RawBinding)
return `${column} < ?`
case "$lte":
bindings.push(value as Knex.RawBinding)
return `${column} <= ?`
case "$like":
bindings.push(value as Knex.RawBinding)
return `${column} like ?`
case "$ilike":
bindings.push(value as Knex.RawBinding)
return `${column} ilike ?`
case "$is":
if (value === null) {
return `${column} is null`
}
bindings.push(value as Knex.RawBinding)
return `${column} is ?`
default:
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Invalid operator: ${operator}`
)
}
}
function buildInArraySql(
column: string,
values: Knex.RawBinding[],
negated: boolean
): SqlFragment | undefined {
if (!values.length) {
return negated ? undefined : { sql: "1 = 0", bindings: [] }
}
// Use `any(array[...])` so MikroORM's formatQuery inlines values as
// `array['a','b']` instead of the invalid `any('a','b')` from a single array
// binding with `any(?)`.View on GitHub (pinned to 5e06e544a2)
Solutions
- Replace the unsupported operator with a supported one ($like for substring, $gte already supported for numerics — check the FilterOperator union)
- Build the filter from a whitelist of operators in your own code
- Check the emitted SQL/log to confirm the operator mapping
Example fix
// before
filters: { title: { $regex: "shirt" } }
// after
filters: { title: { $like: "%shirt%" } } Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED = new Set(['$eq','$ne','$gt','$gte','$lt','$lte','$in','$nin','$like','$ilike','$re','$contains','$startsWith','$endsWith','$null'])
for (const op of Object.keys(filter)) if (op.startsWith('$') && !ALLOWED.has(op)) throw new Error(`unsupported operator ${op}`) Type guard
const isSupportedOperator = (op: string): boolean => !op.startsWith('$') || ALLOWED_OPS.has(op) Try / catch
try { await query.graph(...) } catch (e) { if (/Invalid operator/.test(e.message)) translate filter and retry; else throw e } Prevention
- Build filters from a whitelist map, not raw user input
- Prefer $like/$ilike over regex-style operators
When it happens
Trigger: Passing an unsupported operator in query filters, e.g. `{ price: { $gte: 10, $regex: "x" } }` or a typo like `$contains` where `$like` is expected, to remoteQuery/query.graph with cross-module SQL filters.
Common situations: Porting Mongo-style filter syntax ($regex, $nor, $elemMatch) to Medusa's query API, or typos in dynamic filter builders.
Related errors
- Duplicate cross-module join target table "${join.target.tabl
- Cross-module join for "${join.target.table}" cannot be its o
- Cross-module join for "${join.target.table}" references unkn
- invalid_data
- ${message}
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/80321c8bb5943d01.
Report an issue: GitHub.