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

  1. Upgrade spring-ai-anthropic / anthropic-java SDK to a version that captures signatures from the correct streaming events
  2. Check that no proxy or interceptor strips signature_delta events from the stream
  3. Disable thinking replay expectations: if you do not need to send thinking back, ignore the warning
  4. Verify the model actually supports/returns signed thinking (not redacted thinking blocks)
  5. 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

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


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)