{"record":{"id":"5f86074e706f981f","repo":"medusajs/medusa","slug":"message-5f8607","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/providers/search-postgres/src/utils/filters.ts","lineNumber":6,"sourceCode":"import { SearchTypes } from \"@medusajs/framework/types\"\nimport { MedusaError } from \"@medusajs/framework/utils\"\nimport { IndexPlan, PlannedField } from \"./plan\"\n\nfunction fail(message: string): never {\n  throw new MedusaError(MedusaError.Types.NOT_ALLOWED, message)\n}\n\nexport type SqlFragment = {\n  sql: string\n  params: unknown[]\n}\n\n/**\n * Builds a JSONB path expression against the `indexed` column for a dotted\n * field path. `variants.color` becomes `indexed->'variants'->'color'`.\n */\nexport function jsonbPath(path: string, asText = false): string {\n  const segments = path.split(\".\")\n  let expr = \"indexed\"\n\n  for (let i = 0; i < segments.length; i++) {\n    const segment = segments[i].replace(/'/g, \"''\")\n    const isLast = i === segments.length - 1","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/search-postgres/src/utils/filters.ts#L1-L24","documentation":"Thrown by the search-postgres module's filter compiler when it encounters a filter expression it cannot translate into SQL. The fail() helper wraps the message in a MedusaError of type NOT_ALLOWED, and it is reached from castScalar, comparisonSql, arrayContainsSql, and fieldPredicate when a filter uses an unsupported operator, an uncastable scalar value, or a field that cannot be predicated on.","triggerScenarios":"Calling search with a filter whose operator is not supported for the field's kind (e.g. $lt on a text field), passing a scalar that cannot be cast to the field type (e.g. a string for a number field), using array containment on a non-array field, or filtering on a field missing from the index plan.","commonSituations":"Passing MeiliSearch-style filter syntax to the Postgres search provider, filtering on an attribute not marked searchable in the index settings, mismatched filter value types coming from loose JSON input, or upgrading search-postgres where supported operators changed.","solutions":["Check the exact field and operator in the filter that triggered the message and verify the field exists and is searchable in the index plan (see utils/plan.ts)","Use an operator supported for that field kind, or cast the value to the field's declared type before sending","Filter only on fields declared in your index settings / search settings for the index in question","If you need unsupported semantics (e.g. full-text operators), move that logic out of the filter and into the query or post-filter in application code"],"exampleFix":"// before\nawait query.graph({\n  entity: \"product\",\n  filters: { title: { $lt: \"abc\" } }, // $lt unsupported on text\n})\n// after\nawait query.graph({\n  entity: \"product\",\n  filters: { title: { $like: \"%abc%\" } },\n})","handlingStrategy":"validation","validationCode":"const SUPPORTED: Record<string, string[]> = {\n  text: [\"$eq\", \"$ne\", \"$like\", \"$in\", \"$nin\"],\n  number: [\"$eq\", \"$ne\", \"$lt\", \"$lte\", \"$gt\", \"$gte\", \"$in\"],\n  boolean: [\"$eq\", \"$ne\"],\n}\n\nfunction validateFilter(field: string, kind: keyof typeof SUPPORTED, op: string) {\n  if (!SUPPORTED[kind].includes(op)) {\n    throw new Error(`Unsupported operator ${op} for ${kind} field ${field}`)\n  }\n}","typeGuard":"function isSupportedOperator(op: string, kind: string): boolean {\n  const ops: Record<string, string[]> = {\n    text: [\"$eq\", \"$ne\", \"$like\", \"$in\", \"$nin\"],\n    number: [\"$eq\", \"$ne\", \"$lt\", \"$lte\", \"$gt\", \"$gte\", \"$in\"],\n  }\n  return (ops[kind] ?? []).includes(op)\n}","tryCatchPattern":"try {\n  await searchModule.search({ index, query, filters })\n} catch (e) {\n  if (e instanceof MedusaError && e.type === MedusaError.Types.NOT_ALLOWED) {\n    // unsupported filter: log filter shape and fall back to broader search + app-side filtering\n    logger.warn(`Unsupported filter: ${e.message}`)\n  } else throw e\n}","preventionTips":["Validate filter operators against the field kind before calling search","Only filter on fields declared searchable in index settings","Add a thin wrapper around search calls that type-checks filter values"],"tags":["search-postgres","filters","invalid-operator","medusa-error"],"backgroundTag":"invalid-filter-expression","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}