bug: prevent crash on empty system message content array in Anthropic-family transforms - #1742
bug: prevent crash on empty system message content array in Anthropic-family transforms#1742ErenAta16 wants to merge 2 commits into
Conversation
The Anthropic chatComplete system-message transform read `msg.content[0].text` to detect array-form content without first checking the array was non-empty. A request with a system or developer message whose content is an empty array (`content: []`) therefore threw `TypeError: Cannot read properties of undefined (reading 'text')` instead of being handled, surfacing as a 500 from client-controlled input. The same config is reused by the Vertex Anthropic and Azure AI Inference providers. Use optional chaining so an empty content array is treated as no system content, matching how the sibling messages transform already guards with a length check. Adds a regression test.
…ansform Same defect as the Anthropic chatComplete transform, in the Bedrock Anthropic upload-file config (`BedrockUploadFileTransformerConfig.anthropic`): the system-message transform read `msg.content[0].text` without a length check, so a system/developer message with an empty content array (`content: []`) threw `TypeError: Cannot read properties of undefined (reading 'text')` while building a Bedrock batch-inference file. Use optional chaining so an empty content array yields an empty system string. Adds a regression test that exercises the transform through the exported `BedrockUploadFileTransformerConfig`.
eeshsaxena
left a comment
There was a problem hiding this comment.
The optional chaining here is right, content: [] was definitely throwing before this.
One thing I ran into while looking at it: msg.content[0]?.text is doing double duty. It guards against the empty array, but it's also the only thing deciding whether this is array-form system content at all. So a system message whose first block isn't text still falls through both branches and disappears without any error.
I checked against the current main (the behaviour is the same with your ?. applied, since content[0] exists in these cases and just has no text):
content: [{type:'image', source:{...}}, {type:'text', text:'be concise'}] -> []
content: [{type:'text', text:''}, {type:'text', text:'be concise'}] -> []
content: [{type:'text', text:'be concise'}] -> [{text:'be concise', type:'text'}]
The first case is the one that worries me. Anthropic accepts image blocks in system content, and a leading empty text block shows up in the wild too when something upstream builds the array programmatically. In both, "be concise" is silently dropped rather than sent, and there's no error to tell you it happened. The else if only catches string content, so nothing picks it up.
Would it be worth widening the condition to something like Array.isArray(msg.content) and letting the inner loop deal with the blocks? That keeps your empty-array fix (the loop just doesn't run) and stops the silent drop at the same time. The inner forEach pushes text: _msg.text for every block regardless of type, so it'd probably want to skip or map non-text blocks rather than emit {text: undefined, type:'text'}, but that's arguably a separate cleanup.
Not blocking, the crash fix stands on its own. Mostly flagging it because the empty-array case and the image-first case look like the same underlying assumption, and it'd be a shame to fix one and leave the other.
Description: (required)
Two Anthropic-family system-message transforms decide whether a system/developer message is array-form by reading
msg.content[0].textwithout first checking the array is non-empty:When a request sends a system or developer message whose content is an empty array (
content: []),msg.content[0]isundefinedand the access throws:contentis client-controlled, so a malformed-but-plausible request becomes a 500 instead of being handled. The sibling non-system branches already guard array access withmsg.content.length, so these two paths are the outliers.src/providers/anthropic/chatComplete.ts:AnthropicChatCompleteConfigsystem transform. This config is also spread intoVertexAnthropicChatCompleteConfigand used byazure-ai-inference, so the crash reaches Claude on Vertex and Azure AI Inference too.src/providers/bedrock/uploadFileUtils.ts: theBedrockUploadFileTransformerConfig.anthropicsystem transform, used when building Bedrock batch-inference files for Claude.Both are changed from
msg.content[0].texttomsg.content[0]?.text, so an empty content array is treated as no system content instead of throwing. Non-empty array content is unaffected.Tests Run/Test cases added: (required)
src/providers/anthropic/chatComplete.test.ts: empty system content array no longer throws (returns[]), and array-form system content still transforms as before.src/providers/bedrock/uploadFileUtils.test.ts: same two cases exercised through the exportedBedrockUploadFileTransformerConfig.mainwith the TypeError above and pass with this change; the array-form cases pass before and after.Type of Change: