{"record":{"id":"46c846045c5db5fc","repo":"medusajs/medusa","slug":"deleting-medusa-search-documents-requires-filters","errorCode":null,"errorMessage":"Deleting Medusa search documents requires filters","messagePattern":"Deleting Medusa search documents requires filters","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/search/src/providers/search-medusa/services/medusa-search.ts","lineNumber":174,"sourceCode":"\n    for (const chunk of this.chunkRows(rows)) {\n      await remote.write({\n        upsert_rows: chunk,\n        schema: plan.schema,\n        distance_metric: plan.options.distance_metric,\n      })\n    }\n\n    return this.task(index)\n  }\n\n  async deleteDocuments({\n    index,\n    filters,\n  }: SearchTypes.SearchDeleteDocumentsInput): Promise<SearchTypes.SearchTask> {\n    const compiled = toSearchFilter(filters)\n    if (!compiled) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_ARGUMENT,\n        \"Deleting Medusa search documents requires filters\"\n      )\n    }\n\n    let remaining = true\n    while (remaining) {\n      const response = await this.index(index).write({\n        delete_by_filter: compiled,\n        delete_by_filter_allow_partial: true,\n      })\n      remaining = response.rows_remaining === true\n    }\n\n    return this.task(index)\n  }\n\n  async clearIndex({","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/search/src/providers/search-medusa/services/medusa-search.ts#L156-L192","documentation":"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.","triggerScenarios":"Calling deleteDocuments({ index }) with filters omitted, empty, or containing only clauses that compile to nothing (e.g. empty $and, undefined values).","commonSituations":"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.","solutions":["Pass at least one concrete filter that identifies the documents to delete, e.g. { id: [...] } or a field equality filter","Guard dynamic filter builders: skip the delete call entirely when the compiled filter is empty","For full-index cleanup, use a deliberate index-wide delete/reset API instead of an empty filter"],"exampleFix":"// before\nawait searchProvider.deleteDocuments({ index, filters: undefined })\n// after\nawait searchProvider.deleteDocuments({ index, filters: { product_id: productId } })","handlingStrategy":"type-guard","validationCode":"function hasDeleteFilters(filters: unknown): boolean {\n  return (\n    !!filters &&\n    typeof filters === \"object\" &&\n    Object.keys(filters as object).length > 0\n  )\n}\n\nif (!hasDeleteFilters(filters)) {\n  logger.warn('Skipping deleteDocuments: no filters provided')\n} else {\n  await provider.deleteDocuments({ index, filters })\n}","typeGuard":"interface ConcreteFilter { [k: string]: unknown }\nfunction isConcreteFilter(f: unknown): f is ConcreteFilter {\n  return !!f && typeof f === 'object' && Object.values(f).some((v) => v !== undefined && v !== null)\n}","tryCatchPattern":"try {\n  await provider.deleteDocuments({ index, filters })\n} catch (e) {\n  if (e instanceof MedusaError && e.type === MedusaError.Types.INVALID_ARGUMENT) {\n    // filters compiled to nothing: never retry blindly; fix the filter first\n    logger.error(`deleteDocuments rejected: ${e.message}`)\n  } else throw e\n}","preventionTips":["Never call deleteDocuments without an explicit identifying filter","Short-circuit dynamic filter builders when the result is empty","Use index reset APIs for intentional full deletions"],"tags":["search","delete-documents","missing-filters","validation"],"backgroundTag":"missing-required-filter","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}