spring-projects/spring-ai · warning

Query expansion result does not contain the requested

Error message

Query expansion result does not contain the requested ${numberOfQueries} variants. Returning the input query unchanged.

What it means

After splitting the model response on newlines, MultiQueryExpander checks that the number of variants equals numberOfQueries; if the list is empty or the count mismatches, it warns and returns the original query unchanged. LLMs often return fewer, more, or merged lines, so strict count matching frequently trips.

Solutions

  1. Relax expectations: newer versions remove strict count matching — upgrade spring-ai-rag.
  2. Use a prompt template that demands exactly N lines with no numbering or extra text.
  3. Post-filter blank lines yourself by supplying a custom prompt and parsing tolerant input.
  4. Reduce numberOfQueries or test with a model that follows line-count instructions reliably.

Example fix

// before — strict count triggers fallback often
.prompt(DEFAULT_USER_TEXT)
// "Generate {number} search queries..."

// after — template that enforces one query per line, no numbering
MultiQueryExpander.builder()
    .chatClient(chatClient)
    .prompt("Generate exactly {number} search queries, one per line, no numbering, no extra text for: {query}")
    .numberOfQueries(3)
    .build();
Defensive patterns

Strategy: fallback

Validate before calling

String response = model.call(prompt);
long lines = response == null ? 0 : Arrays.stream(response.split("\n")).filter(s -> !s.isBlank()).count();
if (lines != expectedNumberOfQueries) logger.warn("Expansion returned {} of {} lines", lines, expectedNumberOfQueries);

Try / catch

List<Query> expanded = expander.expand(query);
if (expanded.size() == 1 && expanded.get(0).equals(query)) {
    logger.info("Expansion fallback; proceeding with original query");
}

Prevention

When it happens

Trigger: expand() -> response.split("\n") yields a list whose size differs from this.numberOfQueries (or is empty).

Common situations: Model returns numbered or blank-line-separated queries causing miscount; model returns 1 line instead of N; extra explanation lines around the queries; reasoning models returning prose.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at spring-ai-rag/src/main/java/org/springframework/ai/rag/preretrieval/query/expansion/MultiQueryExpander.java:120

		}

		var response = this.chatClient.prompt()
			.user(user -> user.text(this.promptTemplate.getTemplate())
				.param("number", this.numberOfQueries)
				.param("query", query.text()))
			.call()
			.content();

		if (response == null) {
			logger.warn("Query expansion result is null. Returning the input query unchanged.");
			return List.of(query);
		}

		var queryVariants = Arrays.asList(response.split("\n"));

		if (CollectionUtils.isEmpty(queryVariants) || this.numberOfQueries != queryVariants.size()) {
			if (logger.isWarnEnabled()) {
				logger.warn("Query expansion result does not contain the requested " + this.numberOfQueries
						+ " variants. Returning the input query unchanged.");
			}
			return List.of(query);
		}

		var queries = queryVariants.stream()
			.filter(StringUtils::hasText)
			.map(queryText -> query.mutate().text(queryText).build())
			.collect(Collectors.toList());

		if (this.includeOriginal) {
			logger.debug("Including the original query in the result");
			queries.add(0, query);
		}

		return queries;
	}

View on GitHub (pinned to 98a7beda4f)