Skip to content

Commit 283d0c6

Browse files
Fix NPE in AnthropicApi StreamHelper (#3755)
- When the error event occurs, the ChatCompletionResponseBuilder is empty and hence the contentBlockReference.get() throws NPE. - Add null check to unhandled event in addition to the logging the event type - Add test to verify the usecase Fixes #3740 Auto-cherry-pick to 1.0.x Signed-off-by: Ilayaperumal Gopinathan <[email protected]>
1 parent dbaa608 commit 283d0c6

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/api/StreamHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import java.util.List;
2121
import java.util.concurrent.atomic.AtomicReference;
2222

23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
2326
import org.springframework.ai.anthropic.api.AnthropicApi.ChatCompletionResponse;
2427
import org.springframework.ai.anthropic.api.AnthropicApi.ContentBlock;
2528
import org.springframework.ai.anthropic.api.AnthropicApi.ContentBlock.Type;
@@ -56,6 +59,8 @@
5659
*/
5760
public class StreamHelper {
5861

62+
private static final Logger logger = LoggerFactory.getLogger(StreamHelper.class);
63+
5964
public boolean isToolUseStart(StreamEvent event) {
6065
if (event == null || event.type() == null || event.type() != EventType.CONTENT_BLOCK_START) {
6166
return false;
@@ -216,7 +221,11 @@ else if (event.type().equals(EventType.MESSAGE_STOP)) {
216221
}
217222
else {
218223
// Any other event types that should propagate upwards without content
224+
if (contentBlockReference.get() == null) {
225+
contentBlockReference.set(new ChatCompletionResponseBuilder());
226+
}
219227
contentBlockReference.get().withType(event.type().name()).withContent(List.of());
228+
logger.warn("Unhandled event type: {}", event.type().name());
220229
}
221230

222231
return contentBlockReference.get().build();
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.springframework.ai.anthropic.api;
2+
3+
import java.util.concurrent.atomic.AtomicReference;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
import org.springframework.ai.anthropic.api.StreamHelper.ChatCompletionResponseBuilder;
8+
9+
import static org.assertj.core.api.Assertions.assertThat;
10+
11+
/**
12+
* @author Ilayaperumal Gopinathan
13+
*/
14+
class StreamHelperTest {
15+
16+
@Test
17+
void testErrorEventTypeWithEmptyContentBlock() {
18+
AnthropicApi.ErrorEvent errorEvent = new AnthropicApi.ErrorEvent(AnthropicApi.EventType.ERROR,
19+
new AnthropicApi.ErrorEvent.Error("error", "error message"));
20+
AtomicReference<ChatCompletionResponseBuilder> contentBlockReference = new AtomicReference<>();
21+
StreamHelper streamHelper = new StreamHelper();
22+
AnthropicApi.ChatCompletionResponse response = streamHelper.eventToChatCompletionResponse(errorEvent,
23+
contentBlockReference);
24+
assertThat(response).isNotNull();
25+
}
26+
27+
}

0 commit comments

Comments
 (0)