jd-opensource/joyagent-jdgenie · error · IllegalArgumentException
Empty or invalid response from LLM
Error message
Empty or invalid response from LLM
What it means
LLM.ask parses the chat-completion HTTP response and throws IllegalArgumentException when the JSON has no choices array, an empty choices array, or the first choice's message.content is null. It guards the contract that a successful completion always contains text content.
Solutions
- Log/inspect the raw response to see what was actually returned
- Verify the model name, endpoint URL, and API version are compatible
- Handle non-200 responses before parsing choices
- Add retry with backoff for transient empty responses
Example fix
// before
return llm.ask(messages);
// after
try {
return llm.ask(messages);
} catch (IllegalArgumentException e) {
log.error("llm empty response, retrying");
return llm.ask(messages);
} Defensive patterns
Strategy: try-catch
Validate before calling
// validate HTTP 200 and non-empty body before calling ask
Try / catch
try {
String content = llm.ask(messages);
} catch (IllegalArgumentException e) {
log.error("empty llm response");
throw new RetryableException(e);
} Prevention
- Verify endpoint/model/API version compatibility
- Retry transient empty responses with backoff
- Log raw responses to detect schema changes
When it happens
Trigger: Calling LLM.ask when the LLM endpoint returns a malformed/empty body, an error JSON without choices, a truncated response, or a choice whose message has no content field.
Common situations: Wrong API base URL or incompatible endpoint, model returns a refusal/error payload, content-filtered responses, proxy returning an HTML error page, or API version change altering the response schema.
Related errors
- Invalid or empty response from LLM
- 解析llm json结果失败
- Invalid tool_choice: " + toolChoice
- Error in generating model output
- Error in code parsing
AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08).
Data as JSON: /api/errors/72ebe4f18b92a880.
Report an issue: GitHub.
Appendix: source
Thrown at genie-backend/src/main/java/com/jd/genie/agent/llm/LLM.java:255
}
log.info("{} call llm ask request {}", context.getRequestId(), JSONObject.toJSONString(params));
// 处理非流式请求
if (!stream) {
params.put("stream", false);
// 调用 API
CompletableFuture<String> future = callOpenAI(params);
return future.thenApply(response -> {
try {
// 解析响应
log.info("{} call llm response {}", context.getRequestId(), response);
JsonNode jsonResponse = objectMapper.readTree(response);
JsonNode choices = jsonResponse.get("choices");
if (choices == null || choices.isEmpty() || choices.get(0).get("message").get("content") == null) {
throw new IllegalArgumentException("Empty or invalid response from LLM");
}
return choices.get(0).get("message").get("content").asText();
} catch (IOException e) {
throw new CompletionException(e);
}
});
} else {
// 处理流式请求
params.put("stream", true);
// 调用流式 API
return callOpenAIStream(params);
}
} catch (Exception e) {
log.error("{} Unexpected error in ask: {}", e.getMessage(), e);
CompletableFuture<String> future = new CompletableFuture<>();
future.completeExceptionally(e);
return future;View on GitHub (pinned to 2417e0b8b6)