spring-projects/spring-ai · warning
Thinking block completed without a signature — skipping…
Error message
Thinking block completed without a signature — skipping replay capture
What it means
A warning emitted during streaming when a thinking block finishes but Anthropic never delivered a signature field. Without a signature the thinking content cannot be replayed in a subsequent request (Anthropic requires signed thinking for extended-thinking multi-turn), so it is skipped from thinkingContents. Responses relying on replayed thinking will be missing that block.
Solutions
- Upgrade spring-ai-anthropic / anthropic-java SDK to a version that captures signatures from the correct streaming events
- Check that no proxy or interceptor strips signature_delta events from the stream
- Disable thinking replay expectations: if you do not need to send thinking back, ignore the warning
- Verify the model actually supports/returns signed thinking (not redacted thinking blocks)
- Test with non-streaming call to confirm signatures are present in the blocking response
Example fix
// before
// relying on streamed thinking to be replayed
ChatResponse resp = chatModel.call(new Prompt(prompt, opts)); // warning: no signature
// after
// verify stream integrity or capture signature explicitly
client.messages().stream(...).forEach(event -> {
if (event.signatureDelta() != null) {
signatureBuilder.append(event.signatureDelta().signature());
}
}); Defensive patterns
Strategy: retry
Type guard
boolean hasValidThinking(Generation g) {
return g.getOutput().getMetadata().containsKey("thinking")
&& g.getOutput().getMetadata().get("signature") != null;
} Try / catch
// streaming path: detect missing signatures and retry non-streaming
if (sawThinkingWithoutSignature) {
logger.warn("Signature missing in stream; falling back to blocking call");
response = chatModel.call(new Prompt(prompt, options)); // blocking response carries signature
} Prevention
- Keep the anthropic-java SDK and spring-ai-anthropic versions aligned so signature_delta events are handled
- Avoid proxies/interceptors that rewrite or filter streaming SSE events
- If you rely on thinking replay in multi-turn, verify signatures exist before sending the next request
- Prefer blocking calls when thinking replay is critical and streaming is not required
When it happens
Trigger: Streaming responses with extended thinking enabled where the message_delta/stop event arrives with an empty or absent signature_delta for the current thinking block — e.g. redacted thinking, API behavior changes, or truncated streams.
Common situations: Using streaming with thinking enabled and a proxy that drops signature deltas; multi-turn conversations where the previous assistant turn's thinking had no signature; SDK/model version mismatch where signature events are named differently.
Related errors
- Anthropic cache breakpoint limit (4) reached. Additional…
- Anthropic Citations API requires all documents to have…
- Currently only one tool call is supported per message!
- Currently only one tool call is supported per message!
- Enforcing streaming of the model pull request
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/b079258c771f2bde.
Report an issue: GitHub.
Appendix: source
Thrown at models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java:1719
this.currentThinking.set(true);
this.currentThinkingAccumulator.setLength(0);
this.currentThinkingSignature.set(null);
}
void appendThinking(String thinking) {
this.currentThinkingAccumulator.append(thinking);
}
void setThinkingSignature(String signature) {
this.currentThinkingSignature.set(signature);
}
void finishThinking() {
if (this.currentThinking.get()) {
String signature = this.currentThinkingSignature.get();
if (signature == null) {
if (logger.isWarnEnabled()) {
logger.warn("Thinking block completed without a signature — skipping replay capture");
}
}
else {
this.thinkingContents
.add(AnthropicThinkingContent.thinking(this.currentThinkingAccumulator.toString(), signature));
}
}
this.currentThinking.set(false);
this.currentThinkingAccumulator.setLength(0);
this.currentThinkingSignature.set(null);
}
void addThinkingContent(AnthropicThinkingContent thinkingContent) {
this.thinkingContents.add(thinkingContent);
}
/**
* Appends partial JSON to the current tool's input accumulator.View on GitHub (pinned to 98a7beda4f)