{"record":{"id":"72ebe4f18b92a880","repo":"jd-opensource/joyagent-jdgenie","slug":"empty-or-invalid-response-from-llm","errorCode":null,"errorMessage":"Empty or invalid response from LLM","messagePattern":"Empty or invalid response from LLM","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"genie-backend/src/main/java/com/jd/genie/agent/llm/LLM.java","lineNumber":255,"sourceCode":"            }\n\n            log.info(\"{} call llm ask request {}\", context.getRequestId(), JSONObject.toJSONString(params));\n            // 处理非流式请求\n            if (!stream) {\n                params.put(\"stream\", false);\n\n                // 调用 API\n                CompletableFuture<String> future = callOpenAI(params);\n\n                return future.thenApply(response -> {\n                    try {\n                        // 解析响应\n                        log.info(\"{} call llm response {}\", context.getRequestId(), response);\n                        JsonNode jsonResponse = objectMapper.readTree(response);\n                        JsonNode choices = jsonResponse.get(\"choices\");\n\n                        if (choices == null || choices.isEmpty() || choices.get(0).get(\"message\").get(\"content\") == null) {\n                            throw new IllegalArgumentException(\"Empty or invalid response from LLM\");\n                        }\n\n                        return choices.get(0).get(\"message\").get(\"content\").asText();\n                    } catch (IOException e) {\n                        throw new CompletionException(e);\n                    }\n                });\n            } else {\n                // 处理流式请求\n                params.put(\"stream\", true);\n                // 调用流式 API\n                return callOpenAIStream(params);\n            }\n        } catch (Exception e) {\n            log.error(\"{} Unexpected error in ask: {}\", e.getMessage(), e);\n            CompletableFuture<String> future = new CompletableFuture<>();\n            future.completeExceptionally(e);\n            return future;","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/genie-backend/src/main/java/com/jd/genie/agent/llm/LLM.java#L237-L273","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nreturn llm.ask(messages);\n// after\ntry {\n    return llm.ask(messages);\n} catch (IllegalArgumentException e) {\n    log.error(\"llm empty response, retrying\");\n    return llm.ask(messages);\n}","handlingStrategy":"try-catch","validationCode":"// validate HTTP 200 and non-empty body before calling ask","typeGuard":null,"tryCatchPattern":"try {\n    String content = llm.ask(messages);\n} catch (IllegalArgumentException e) {\n    log.error(\"empty llm response\");\n    throw new RetryableException(e);\n}","preventionTips":["Verify endpoint/model/API version compatibility","Retry transient empty responses with backoff","Log raw responses to detect schema changes"],"tags":["llm","json","response-parsing"],"backgroundTag":"unexpected-response-shape","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}