medusajs/medusa · error · MedusaError

${message}

Error message

${message}

What it means

This is the facet-building error channel of the search-medusa provider: buildFacetQueries calls fail() with a NOT_ALLOWED MedusaError for facet requests the provider cannot serve. Known messages: 'Unknown facet field "<name>"' (field not in the index plan) and rejection of type "stats" facets because the cloud service does not expose min/max aggregates.

Source

Thrown at packages/modules/search/src/providers/search-medusa/utils/facets.ts:31

  { type: "range" }
>
type ValueFacetRequest = {
  field: string
  type?: "value"
  limit?: number
  sort?: "count" | "alpha"
  query?: string
}

export type FacetQuery = {
  field: string
  request: RangeFacetRequest | ValueFacetRequest
  range?: RangeFacetRequest["ranges"][number]
  query: IndexQuery
}

function fail(message: string): never {
  throw new MedusaError(MedusaError.Types.NOT_ALLOWED, message)
}

function and(filters: (Filter | undefined)[]): Filter | undefined {
  const present = filters.filter((item): item is Filter => !!item)
  if (!present.length) {
    return undefined
  }
  return present.length === 1 ? present[0] : ["And", present]
}

export function buildFacetQueries(
  input: SearchTypes.ProviderSearchQuery,
  plan: IndexPlan
): FacetQuery[] {
  const requests = (input.search_options?.facets ?? []) as
    | SearchTypes.SearchFacetRequest[]
  const base = toSearchFilter(input.filters, plan)
  const result: FacetQuery[] = []

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Only request facet fields that exist in the index plan/definition; add the missing field as facetable in the index settings
  2. Replace stats facets with range facets (e.g. explicit price buckets), which the provider supports
  3. Keep the storefront facet list in sync with the index schema after model changes

Example fix

// before
search_options: { facets: [{ field: "price", type: "stats" }] }
// after
search_options: {
  facets: [
    {
      field: "price",
      type: "range",
      ranges: [{ to: 50 }, { from: 50, to: 100 }, { from: 100 }],
    },
  ],
}
Defensive patterns

Strategy: validation

Validate before calling

const indexFields = new Set([...]) // derived from index definition
const safeFacets = requestedFacets.filter(
  (f) => indexFields.has(f.field) && f.type !== "stats"
)

Type guard

const isSupportedFacet = (f, indexFields) =>
  indexFields.has(f.field) &&
  f.type !== "stats" &&
  (f.type !== "range" || Array.isArray(f.ranges))

Try / catch

try { await search(...) } catch (e) { if (e instanceof MedusaError && e.type === "not_allowed" && /facet/i.test(e.message)) { return search(..., { facets: [] }) } throw e }

Prevention

When it happens

Trigger: Passing a facet request in search_options.facets referencing a field not defined in the index schema (or not facetable/planned), or sending { type: "stats" } facets, which the Medusa cloud service cannot compute.

Common situations: Requesting facets on a field that exists on the model but was not added to the index definition; renaming/removing an index field while the storefront still requests the old facet; migrating a storefront from Meilisearch-style stats facets (price min/max) to Medusa search.

Related errors


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