spring-projects/spring-ai · warning
No choices returned for prompt: ${prompt}
Error message
No choices returned for prompt: ${prompt} What it means
OpenAiChatModel.internalCall sends a chat completion request to the OpenAI API and checks the returned ChatCompletion. When the API responds successfully but the choices list is empty, Spring AI logs a warning and returns an empty ChatResponse instead of throwing, because there are no generations to build. This usually signals the provider accepted the request but produced no candidate completions.
Source
Thrown at models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiChatModel.java:228
ChatCompletionCreateParams request = this.createRequest(prompt, false);
RequestOptions requestOptions = this.buildRequestOptions(prompt);
ChatModelObservationContext observationContext = ChatModelObservationContext.builder()
.prompt(prompt)
.provider(AiProvider.OPENAI.value())
.build();
ChatResponse response = ChatModelObservationDocumentation.CHAT_MODEL_OPERATION
.observation(this.observationConvention, DEFAULT_OBSERVATION_CONVENTION, () -> observationContext,
this.observationRegistry)
.observe(() -> {
ChatCompletion chatCompletion = this.openAiClient.chat().completions().create(request, requestOptions);
List<ChatCompletion.Choice> choices = chatCompletion.choices();
if (choices.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("No choices returned for prompt: " + prompt);
}
return new ChatResponse(List.of());
}
List<Generation> generations = choices.stream().map(choice -> {
Map<String, Object> metadata = Map.of("id", chatCompletion.id(), "role",
choice.message()._role().asString().isPresent() ? choice.message()._role().asStringOrThrow()
: "",
"index", choice.index(), "finishReason", choice.finishReason().value().toString(),
"refusal", choice.message().refusal().orElse(""), "annotations",
choice.message().annotations().orElse((List) List.of(Map.of())), REASONING_CONTENT,
getReasoningContent(choice));
return buildGeneration(choice, metadata, request);
}).toList();
// Current usage
CompletionUsage usage = chatCompletion.usage().orElse(null);
Usage currentChatResponseUsage = usage != null ? getDefaultUsage(usage) : new EmptyUsage();View on GitHub (pinned to 98a7beda4f)
Solutions
- Check the response object / enable DEBUG logging to see the raw API response and why choices were empty
- If using a proxy or compatible endpoint, verify it returns a standard choices array in the OpenAI chat completion schema
- Rephrase the prompt if content filtering may have suppressed the output
- Handle the empty ChatResponse in your code: check ChatResponse.getResults() is non-empty before reading generations
Example fix
// before
ChatResponse response = chatModel.call(new Prompt("..."));
String text = response.getResult().getOutput().getText(); // NPE if empty
// after
ChatResponse response = chatModel.call(new Prompt("..."));
if (response == null || response.getResults().isEmpty()) {
throw new IllegalStateException("Model returned no completions");
}
String text = response.getResult().getOutput().getText(); Defensive patterns
Strategy: validation
Validate before calling
// after the call
ChatResponse resp = chatModel.call(prompt);
if (resp == null || resp.getResults() == null || resp.getResults().isEmpty()) {
throw new IllegalStateException("OpenAI returned no choices for prompt");
} Prevention
- Check ChatResponse.getResults() non-empty before reading getResult()
- Log raw API responses when using OpenAI-compatible proxies
- Rephrase prompts that may be content-filtered
When it happens
Trigger: Calling OpenAiChatModel.call(prompt) where the OpenAI API returns a ChatCompletion whose choices() list is empty — e.g. the request was filtered by content policy, the API returned a degenerate/empty response, or an unexpected response shape from a non-standard endpoint.
Common situations: Pointing spring.ai.openai.base-url at a non-OpenAI OpenAI-compatible proxy that omits the choices array; safety filtering of flagged prompts; API version changes that change response shape.
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
- No speech response returned for prompt: + prompt
- Chat completion is not supported for this model:
- Failed to read audio speech response
- Failed to read resource:
- Conversion from JSON to %s failed
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/88c6579e4e9e6acc.
Report an issue: GitHub.