alibaba/spring-ai-alibaba · error · RuntimeException
ChatClient successfully returned, but the returned json is i
Error message
ChatClient successfully returned, but the returned json is invalid.
What it means
ParameterParsingNode.apply() asks the ChatClient to return JSON, then deserializes it into the Response record with Jackson. If ChatClient succeeded but its raw output is not valid JSON for the Response schema, JsonProcessingException is caught and rethrown as RuntimeException('ChatClient successfully returned, but the returned json is invalid.').
Source
Thrown at spring-boot-starters/spring-ai-alibaba-starter-builtin-nodes/src/main/java/com/alibaba/cloud/ai/graph/node/ParameterParsingNode.java:203
.chatResponse();
String rawJson = Optional.ofNullable(response)
.orElseThrow(() -> new RuntimeException("chat response is null"))
.getResult()
.getOutput()
.getText();
// Remove Markdown markers
if (rawJson != null) {
rawJson = rawJson.replace("```json", "").replace("```", "").trim();
}
Map<String, Object> result = new HashMap<>();
Response responseJson;
try {
responseJson = OBJECT_MAPPER.readValue(rawJson, Response.class);
}
catch (JsonProcessingException e) {
throw new RuntimeException("ChatClient successfully returned, but the returned json is invalid.");
}
if (responseJson.isSuccess()) {
if (responseJson.data() == null) {
throw new RuntimeException("ChatClient successfully returned, but the returned data is invalid.");
}
result.put(successKey, true);
result.put(dataKey, responseJson.data());
result.put(reasonKey, "success");
}
else {
result.put(successKey, false);
result.put(reasonKey, Optional.ofNullable(responseJson.reason()).orElse("reason is empty"));
}
return result;
}
catch (Exception e) {View on GitHub (pinned to f82da0b50f)
Solutions
- Inspect/parse rawJson: strip markdown code fences before expecting valid JSON
- Strengthen the prompt/instruction to demand strict, fence-free JSON and set a low temperature
- Use ChatClient's structured-output/entity mapping (response entity) instead of manual string parsing
- Catch this RuntimeException downstream and retry the LLM call
Example fix
// before
responseJson = OBJECT_MAPPER.readValue(rawJson, Response.class);
// after
String cleaned = rawJson.replaceAll("^```(json)?|```$", "").trim();
responseJson = OBJECT_MAPPER.readValue(cleaned, Response.class); Defensive patterns
Strategy: try-catch
Validate before calling
String cleaned = rawJson == null ? "" : rawJson.replaceAll("^\\s*```(json)?|```\\s*$", "").trim();
boolean looksLikeJson = cleaned.startsWith("{") && cleaned.endsWith("}"); Type guard
static boolean isParseableResponse(String raw) { try { MAPPER.readValue(raw, Response.class); return true; } catch (Exception e) { return false; } } Try / catch
try { out = node.apply(state); } catch (RuntimeException e) { if (e.getMessage().contains("returned json is invalid")) { retryLlmCall(); } } Prevention
- Instruct the model to output strict JSON without markdown fences
- Use low temperature and few-shot JSON examples in the prompt
- Prefer ChatClient structured output (.entity(Response.class)) over manual parsing
When it happens
Trigger: The LLM reply (rawJson) is malformed JSON, wrapped in markdown code fences, or does not match the Response record fields, making OBJECT_MAPPER.readValue fail.
Common situations: Model ignoring the JSON-format instruction and adding prose or ```json fences; temperature too high causing hallucinated structure; prompt template not requesting strict JSON output.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- 解析模型调用结果出错,请重试
- Failed to parse result
- Nacos config content is not valid JSON, but dot notation was
- 解析默认参数失败: {}
- 解析itemIds字符串失败: {}
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/d1a9159c1d0ad8c9.
Report an issue: GitHub.