spring-projects/spring-ai · error · IllegalStateException

Failed to delete documents by filter

Error message

Failed to delete documents by filter

What it means

ElasticsearchVectorStore.doDelete(Filter.Expression) runs a delete_by_query with a query_string built from the filter; any Exception from the Elasticsearch client is wrapped in IllegalStateException("Failed to delete documents by filter", e). It means the delete-by-query request could not be executed (bad query syntax, connectivity, index problems).

Source

Thrown at vector-stores/spring-ai-elasticsearch-store/src/main/java/org/springframework/ai/vectorstore/elasticsearch/ElasticsearchVectorStore.java:234

	@Override
	public void doDelete(List<String> idList) {
		BulkRequest.Builder bulkRequestBuilder = new BulkRequest.Builder();
		for (String id : idList) {
			bulkRequestBuilder.operations(op -> op.delete(idx -> idx.index(this.options.getIndexName()).id(id)));
		}
		if (bulkRequest(bulkRequestBuilder.build()).errors()) {
			throw new IllegalStateException("Delete operation failed");
		}
	}

	@Override
	public void doDelete(Filter.Expression filterExpression) {
		try {
			this.elasticsearchClient.deleteByQuery(d -> d.index(this.options.getIndexName())
				.query(q -> q.queryString(qs -> qs.query(getElasticsearchQueryString(filterExpression)))));
		}
		catch (Exception e) {
			throw new IllegalStateException("Failed to delete documents by filter", e);
		}
	}

	private BulkResponse bulkRequest(BulkRequest bulkRequest) {
		try {
			return this.elasticsearchClient.bulk(bulkRequest);
		}
		catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public List<Document> doSimilaritySearch(SearchRequest searchRequest) {
		Assert.notNull(searchRequest, "The search request must not be null.");
		try {
			float threshold = (float) searchRequest.getSimilarityThreshold();
			// reverting l2_norm distance to its original value

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect the chained cause for the concrete Elasticsearch error
  2. Test the converter output (getElasticsearchQueryString) manually against the index in Kibana
  3. Verify the index exists (initializeSchema=true or pre-create it) and metadata fields are mapped
  4. Escape/validate filter values that contain Lucene query_string special characters

Example fix

// before: unescaped value breaks query_string
new MetadataValue("status:active AND level");
// after: avoid reserved Lucene chars in metadata values
new MetadataValue("status_active_and_level");
Defensive patterns

Strategy: try-catch

Validate before calling

String qs = store.getElasticsearchQueryString(filterExpression); // test-print before executing
assert !qs.contains(":") || qs.chars().filter(c -> c == ':').count() <= 1;

Try / catch

try {
    vectorStore.delete(filterExpression);
} catch (IllegalStateException e) {
    logger.error("delete_by_query failed for query [{}]", e.getCause() != null ? e.getCause().getMessage() : "", e);
    throw e;
}

Prevention

When it happens

Trigger: Calling vectorStore.delete(Filter.Expression) when the generated query_string is invalid for the index mapping, the index does not exist, or the Elasticsearch client call throws (IO/timeout/auth errors).

Common situations: Filtering on metadata fields not present in the mapping, special characters in filter values breaking query_string syntax, index name misconfigured, cluster unreachable or secured.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/5b4c819ece46a453. Report an issue: GitHub.