spring-projects/spring-ai · warning

Query compression result is null/empty. Returning the input…

Error message

Query compression result is null/empty. Returning the input query unchanged.

What it means

CompressionQueryTransformer.transform asks the chat model to compress a conversation history plus query into a standalone query; when the returned content is null or blank it logs this warning and returns the input query unchanged. The pipeline continues with the un-compressed query instead of failing.

Solutions

  1. Increase maxTokens and verify the compression prompt template renders the history correctly.
  2. Log the raw ChatResponse finish reason to see why content is empty.
  3. Accept the fallback path — ensure callers can work with the original multi-turn query.
  4. Switch to a model that reliably returns text for compression tasks.

Example fix

// before
CompressionQueryTransformer transformer = CompressionQueryTransformer.builder()
    .chatClientBuilder(chatClient.mutate())
    .build();

// after — give the model room to answer
CompressionQueryTransformer transformer = CompressionQueryTransformer.builder()
    .chatClientBuilder(chatClient.mutate()
        .defaultOptions(OpenAiChatOptions.builder().maxTokens(512).build()))
    .build();
Defensive patterns

Strategy: fallback

Validate before calling

// ensure the history isn't truncated to nothing
if (query.history() == null || query.history().isEmpty()) {
    logger.debug("No history to compress; transformer will pass query through");
}

Try / catch

Query transformed = transformer.transform(query);
if (transformed.text().equals(query.text()) && query.history() != null && !query.history().isEmpty()) {
    logger.info("Compression fell back to original query; check model output");
}

Prevention

When it happens

Trigger: transform() calls the compression prompt with history/query params and .call().content() returns null or whitespace (empty completion, content filter, or non-text response).

Common situations: Long histories with a low maxTokens budget yielding empty output; safety filters blocking the compressed output; misconfigured model; reasoning model returning no plain content.

Understand the failure class

Background: "empty response", "returned no data", "empty embeddings": what HTTP 200-with-empty-body errors mean across libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

Thrown at spring-ai-rag/src/main/java/org/springframework/ai/rag/preretrieval/query/transformation/CompressionQueryTransformer.java:90

		PromptAssert.templateHasRequiredPlaceholders(this.promptTemplate, "history", "query");
	}

	@Override
	public Query transform(Query query) {
		Assert.notNull(query, "query cannot be null");

		logger.debug("Compressing conversation history and follow-up query into a standalone query");

		var compressedQueryText = this.chatClient.prompt()
			.user(user -> user.text(this.promptTemplate.getTemplate())
				.param("history", formatConversationHistory(query.history()))
				.param("query", query.text()))
			.call()
			.content();

		if (!StringUtils.hasText(compressedQueryText)) {
			logger.warn("Query compression result is null/empty. Returning the input query unchanged.");
			return query;
		}

		return query.mutate().text(compressedQueryText).build();
	}

	private String formatConversationHistory(List<Message> history) {
		if (history.isEmpty()) {
			return "";
		}

		return history.stream()
			.filter(message -> message.getMessageType().equals(MessageType.USER)
					|| message.getMessageType().equals(MessageType.ASSISTANT))
			.map(message -> "%s: %s".formatted(message.getMessageType(), message.getText()))
			.collect(Collectors.joining("\n"));
	}

View on GitHub (pinned to 98a7beda4f)