{"record":{"id":"1919c9486679f360","repo":"spring-projects/spring-ai","slug":"query-expansion-result-is-null-returning-the-inpu","errorCode":null,"errorMessage":"Query expansion result is null. Returning the input query unchanged.","messagePattern":"Query expansion result is null\\. Returning the input query unchanged\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-rag/src/main/java/org/springframework/ai/rag/preretrieval/query/expansion/MultiQueryExpander.java","lineNumber":112,"sourceCode":"\t}\n\n\t@Override\n\tpublic List<Query> expand(Query query) {\n\t\tAssert.notNull(query, \"query cannot be null\");\n\n\t\tif (logger.isDebugEnabled()) {\n\t\t\tlogger.debug(\"Generating \" + this.numberOfQueries + \" query variants\");\n\t\t}\n\n\t\tvar response = this.chatClient.prompt()\n\t\t\t.user(user -> user.text(this.promptTemplate.getTemplate())\n\t\t\t\t.param(\"number\", this.numberOfQueries)\n\t\t\t\t.param(\"query\", query.text()))\n\t\t\t.call()\n\t\t\t.content();\n\n\t\tif (response == null) {\n\t\t\tlogger.warn(\"Query expansion result is null. Returning the input query unchanged.\");\n\t\t\treturn List.of(query);\n\t\t}\n\n\t\tvar queryVariants = Arrays.asList(response.split(\"\\n\"));\n\n\t\tif (CollectionUtils.isEmpty(queryVariants) || this.numberOfQueries != queryVariants.size()) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"Query expansion result does not contain the requested \" + this.numberOfQueries\n\t\t\t\t\t\t+ \" variants. Returning the input query unchanged.\");\n\t\t\t}\n\t\t\treturn List.of(query);\n\t\t}\n\n\t\tvar queries = queryVariants.stream()\n\t\t\t.filter(StringUtils::hasText)\n\t\t\t.map(queryText -> query.mutate().text(queryText).build())\n\t\t\t.collect(Collectors.toList());\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-rag/src/main/java/org/springframework/ai/rag/preretrieval/query/expansion/MultiQueryExpander.java#L94-L130","documentation":"MultiQueryExpander.expand calls the chat model to generate query variants; when the model returns null content the expander logs this warning and falls back to returning the original query unchanged. Expansion is thus silently skipped rather than failing the retrieval pipeline.","triggerScenarios":"expand() invokes the prompt with number/query params and .call().content() returns null (model produced no content, e.g. content filter, empty completion, or a reasoning-only response).","commonSituations":"ChatModel returning null content due to safety filters; maxTokens too small so no content is generated; misconfigured model returning tool calls instead of text; provider outage producing empty completions.","solutions":["Increase maxTokens / adjust the expansion prompt so the model returns text.","Log the full ChatResponse to see why content is null (finish reason, filter).","Treat the fallback as expected: ensure downstream retrieval handles a single-query list.","Use a different or stronger model for expansion if nulls are frequent."],"exampleFix":"// before\nMultiQueryExpander expander = MultiQueryExpander.builder()\n    .chatClient(chatClient)\n    .numberOfQueries(3)\n    .build();\n\n// after — set explicit options so the model always returns text\nMultiQueryExpander expander = MultiQueryExpander.builder()\n    .chatClient(chatClient)\n    .numberOfQueries(3)\n    .prompt(UPDATE_PROMPT) // tuned prompt\n    .build();\n// and configure model options: maxTokens(512) on the underlying chat model","handlingStrategy":"fallback","validationCode":"// pre-check the chat model config used for expansion\nif (options.getMaxTokens() != null && options.getMaxTokens() < 256) {\n    logger.warn(\"maxTokens too low for query expansion; null content likely\");\n}","typeGuard":null,"tryCatchPattern":"List<Query> queries = expander.expand(new Query(\"original\"));\nif (queries.size() == 1 && queries.get(0).text().equals(\"original\")) {\n    logger.info(\"Expansion fell back to original query; check model output\");\n}","preventionTips":["Check finishReason/filters when content is null instead of only the fallback.","Raise maxTokens for the expansion model.","Use an instruct model that reliably returns plain text.","Design the retrieval pipeline to tolerate single-query results."],"tags":["rag","query-expansion","fallback"],"backgroundTag":"empty-api-response","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}