alibaba/spring-ai-alibaba · error · RuntimeException

ChatClient Call Return Null...

Error message

ChatClient Call Return Null...

What it means

AgentNode.apply throws this RuntimeException when ChatClient.call().content() returns null after the retry-wrapped invocation, i.e. the model produced no textual content. The node logs a warning then fails fast because downstream nodes expect a non-null string output under outputKey.

Source

Thrown at spring-boot-starters/spring-ai-alibaba-starter-builtin-nodes/src/main/java/com/alibaba/cloud/ai/graph/node/AgentNode.java:134

	}

	@Override
	public Map<String, Object> apply(OverAllState state) throws Exception {
		String userPrompt = new PromptTemplate(this.userPrompt).render(state.data());
		String systemPrompt = new PromptTemplate(this.systemPrompt).render(state.data());
		String output = switch (this.strategy) {
			case TOOL_CALLING, REACT -> {
				// Retry mechanism
				try {
					yield this.retryTemplate.execute(retryContext -> {
						String content = this.chatClient.prompt(systemPrompt)
							.toolCallbacks(this.toolCallbacks)
							.user(userPrompt)
							.call()
							.content();
						if (content == null) {
							logger.warn("ChatClient Call Return Null...");
							throw new RuntimeException("ChatClient Call Return Null...");
						}
						return content;
					});
				}
				catch (Exception e) {
					logger.error("Attempted to the maximum number of times but still failed!");
					yield null;
				}
			}
		};
		return Map.of(this.outputKey, output == null ? "" : output);
	}

	public static Builder builder() {
		return new Builder();
	}

	public static class Builder {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Check the model response in logs to see why content is null (tool calls, filtering, token limit)
  2. Raise max_tokens or adjust prompts so the model produces final text
  3. Verify tool execution/conversion so the loop ends with a textual answer
  4. Wrap apply/call sites in try-catch and provide a fallback output value

Example fix

// before
String content = chatClient.prompt().user(userPrompt).call().content();
// after
String content = chatClient.prompt().user(userPrompt).call().content();
if (content == null || content.isBlank()) { content = "(no content generated)"; }
Defensive patterns

Strategy: try-catch

Validate before calling

// verify model reachable and producing content in a preflight call
String probe = chatClient.prompt().user("ping").call().content();
if (probe == null || probe.isBlank()) throw new IllegalStateException("model returns empty content");

Try / catch

try {
    output = agentNode.apply(state);
} catch (RuntimeException e) {
    if (e.getMessage().contains("Return Null")) {
        state.put(outputKey, fallbackAnswer);
    } else throw e;
}

Prevention

When it happens

Trigger: The chat model returns an empty/no-content response (e.g. the response contains only tool calls that were not executed, a stop with no text, or an empty completion) while running the agent's RetryTemplate callback.

Common situations: Model configured with tools but no final text answer generated; max_tokens set so low the response is empty; provider returns empty content on safety-filtered prompts; using a model/adapter whose content mapping yields null.

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


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