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

  1. Inspect/parse rawJson: strip markdown code fences before expecting valid JSON
  2. Strengthen the prompt/instruction to demand strict, fence-free JSON and set a low temperature
  3. Use ChatClient's structured-output/entity mapping (response entity) instead of manual string parsing
  4. 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

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


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/d1a9159c1d0ad8c9. Report an issue: GitHub.