medusajs/medusa · error · MedusaError
${message}
Error message
${message} What it means
This is the filter-normalization error channel (filters.ts fail()): toSearchFilter/normalizeFacetRequests throw NOT_ALLOWED when a search filter cannot be translated to the provider's filter API — typically unsupported filter operators or values that don't match the planned field type (see the coerce/plan mapping).
Source
Thrown at packages/modules/search/src/providers/search-medusa/utils/filters.ts:7
import { SearchTypes } from "@medusajs/framework/types"
import { MedusaError } from "@medusajs/framework/utils"
import type { Filter } from "./api-types"
import { IndexPlan, PlannedField } from "./plan"
function fail(message: string): never {
throw new MedusaError(MedusaError.Types.NOT_ALLOWED, message)
}
function coerce(value: unknown, planned?: PlannedField): unknown {
if (value instanceof Date) {
return value.toISOString()
}
if (planned?.is_date && typeof value === "string") {
return new Date(value).toISOString()
}
return value
}
function globEscape(value: string): string {
return value.replace(/([*?[\]\\])/g, "\\$1")
}
function sqlLikeToGlob(value: string): string {
return valueView on GitHub (pinned to 5e06e544a2)
Solutions
- Coerce query params to the field's declared type before passing filters (numbers for numeric fields, ISO strings for dates)
- Filter only on fields present and filterable in the index definition
- Catch and log the MedusaError message — it names the exact field/value that failed normalization
Example fix
// before
filters: { price: { gte: req.query.minPrice } } // string from query string
// after
filters: {
price: {
gte: req.query.minPrice ? Number(req.query.minPrice) : undefined,
},
}
Defensive patterns
Strategy: validation
Validate before calling
function coerceFilters(filters, spec) {
const out = {}
for (const [field, cond] of Object.entries(filters)) {
if (!spec[field]) continue
out[field] = Object.fromEntries(
Object.entries(cond).map(([op, v]) => [
op,
spec[field] === "date" ? new Date(v).toISOString() : spec[field] === "number" ? Number(v) : v,
])
)
}
return out
} Type guard
const isCoercibleFilterValue = (v, type) => type === "number" ? !Number.isNaN(Number(v)) : type === "date" ? !Number.isNaN(Date.parse(v)) : typeof v === "string"
Try / catch
try { await search(...) } catch (e) { if (e instanceof MedusaError && e.type === "not_allowed") { /* log e.message naming the bad filter, strip it, retry */ } throw e } Prevention
- Parse and coerce query params to typed filter values before calling search
- Only filter on fields declared in the index
- Centralize filter construction in one helper with a field-type spec map
When it happens
Trigger: Passing input.filters with an operator or value shape the provider cannot map onto a planned field: filtering a date field with a non-parsable value, filtering on an unknown/unplanned field, or a combination the provider's Filter model rejects.
Common situations: Storefront filter code sending raw query-string values (strings for numeric fields), filters referencing fields removed from the index after a settings change, or reusing filter payloads built for a different search provider (Meilisearch/Algolia syntax).
Related errors
- Invalid operator: ${operator}
- ${message}
- Deleting Medusa search documents requires filters
- Medusa search accepts at most ${MAX_MULTI_QUERIES} queries p
- A Medusa search document exceeds the ${MAX_WRITE_BYTES}-byte
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/2536160be439e49a.
Report an issue: GitHub.