spring-projects/spring-ai · error · RuntimeException

Bad Request: %s

Error message

Bad Request: %s

What it means

GemFireVectorStore.handleHttpClientException maps a WebClientResponseException with HTTP 400 BAD_REQUEST to RuntimeException("Bad Request: %s"). The server rejected the request payload or parameters sent to the GemFire REST API as malformed or invalid.

Source

Thrown at vector-stores/spring-ai-gemfire-store/src/main/java/org/springframework/ai/vectorstore/gemfire/GemFireVectorStore.java:344

			.block();
	}

	/**
	 * Handles exceptions that occur during HTTP client operations and maps them to
	 * appropriate runtime exceptions.
	 * @param ex the exception that occurred during HTTP client operation
	 * @return a mapped runtime exception corresponding to the HTTP client exception
	 */
	private Throwable handleHttpClientException(Throwable ex) {
		if (!(ex instanceof WebClientResponseException clientException)) {
			throw new RuntimeException(String.format("Got an unexpected error: %s", ex));
		}

		if (clientException.getStatusCode().equals(org.springframework.http.HttpStatus.NOT_FOUND)) {
			throw new RuntimeException(String.format("Index %s not found: %s", this.indexName, ex));
		}
		else if (clientException.getStatusCode().equals(org.springframework.http.HttpStatus.BAD_REQUEST)) {
			throw new RuntimeException(String.format("Bad Request: %s", ex));
		}
		else {
			throw new RuntimeException(String.format("Got an unexpected HTTP error: %s", ex));
		}
	}

	@Override
	public VectorStoreObservationContext.Builder createObservationContextBuilder(String operationName) {
		return VectorStoreObservationContext.builder(VectorStoreProvider.GEMFIRE.value(), operationName)
			.collectionName(this.indexName)
			.dimensions(this.embeddingModel.dimensions())
			.fieldName(EMBEDDINGS);
	}

	public static class CreateRequest {

		@JsonProperty("name")
		private final String indexName;

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect the chained exception message for the server's 400 detail
  2. Validate request parameters (k, threshold, filter expressions) produce valid GemFire OQL/payloads
  3. Confirm embedding dimensions match the index configuration
  4. Check the GemFire REST API version/path expected by your server release

Example fix

// before: unescaped quote breaks the server-side query
new Filter.Expression(ExpressionType.EQ, new MetadataKey("title"), new MetadataValue("it's here"));
// after: sanitize metadata values before storing/querying
new Filter.Expression(ExpressionType.EQ, new MetadataKey("title"), new MetadataValue("its here"));
Defensive patterns

Strategy: try-catch

Validate before calling

Objects.requireNonNull(k, "k must not be null");
Assert.isTrue(k > 0 && k <= 1000, "k out of range");
// also sanitize metadata values of OQL-special characters

Try / catch

try {
    vectorStore.similaritySearch(SearchRequest.builder().query(q).topK(k).build());
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("Bad Request")) {
        logger.error("GemFire rejected request: {}", e.getMessage(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Any GemFire vector store operation whose REST request the server answers with 400: malformed query parameters (e.g. invalid limit/k, bad OQL produced by a filter), or an invalid JSON body in put/create-index calls.

Common situations: Illegal characters or OQL syntax in filter values, embedding dimension mismatch producing an invalid request body, wrong API path/version for the GemFire server, or overly large payloads.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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