medusajs/medusa · error · MedusaError

Deleting Medusa search documents requires filters

Error message

Deleting Medusa search documents requires filters

What it means

Thrown by the Medusa search provider's deleteDocuments when the delete request has no usable filters — toSearchFilter(filters) compiles to null. Since deletion without a filter would wipe the index, the provider requires at least one concrete filter and rejects with INVALID_ARGUMENT.

Source

Thrown at packages/modules/search/src/providers/search-medusa/services/medusa-search.ts:174

    for (const chunk of this.chunkRows(rows)) {
      await remote.write({
        upsert_rows: chunk,
        schema: plan.schema,
        distance_metric: plan.options.distance_metric,
      })
    }

    return this.task(index)
  }

  async deleteDocuments({
    index,
    filters,
  }: SearchTypes.SearchDeleteDocumentsInput): Promise<SearchTypes.SearchTask> {
    const compiled = toSearchFilter(filters)
    if (!compiled) {
      throw new MedusaError(
        MedusaError.Types.INVALID_ARGUMENT,
        "Deleting Medusa search documents requires filters"
      )
    }

    let remaining = true
    while (remaining) {
      const response = await this.index(index).write({
        delete_by_filter: compiled,
        delete_by_filter_allow_partial: true,
      })
      remaining = response.rows_remaining === true
    }

    return this.task(index)
  }

  async clearIndex({

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Pass at least one concrete filter that identifies the documents to delete, e.g. { id: [...] } or a field equality filter
  2. Guard dynamic filter builders: skip the delete call entirely when the compiled filter is empty
  3. For full-index cleanup, use a deliberate index-wide delete/reset API instead of an empty filter

Example fix

// before
await searchProvider.deleteDocuments({ index, filters: undefined })
// after
await searchProvider.deleteDocuments({ index, filters: { product_id: productId } })
Defensive patterns

Strategy: type-guard

Validate before calling

function hasDeleteFilters(filters: unknown): boolean {
  return (
    !!filters &&
    typeof filters === "object" &&
    Object.keys(filters as object).length > 0
  )
}

if (!hasDeleteFilters(filters)) {
  logger.warn('Skipping deleteDocuments: no filters provided')
} else {
  await provider.deleteDocuments({ index, filters })
}

Type guard

interface ConcreteFilter { [k: string]: unknown }
function isConcreteFilter(f: unknown): f is ConcreteFilter {
  return !!f && typeof f === 'object' && Object.values(f).some((v) => v !== undefined && v !== null)
}

Try / catch

try {
  await provider.deleteDocuments({ index, filters })
} catch (e) {
  if (e instanceof MedusaError && e.type === MedusaError.Types.INVALID_ARGUMENT) {
    // filters compiled to nothing: never retry blindly; fix the filter first
    logger.error(`deleteDocuments rejected: ${e.message}`)
  } else throw e
}

Prevention

When it happens

Trigger: Calling deleteDocuments({ index }) with filters omitted, empty, or containing only clauses that compile to nothing (e.g. empty $and, undefined values).

Common situations: Fire-and-forget cleanup jobs that pass only an index, optional chaining producing undefined filters ({ filters: maybeFilters?.x }), or building filters dynamically so they end up empty at runtime.

Related errors


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