AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Silent Data Corruption: `_Convert_to_v1_from_anthropic` Mutates `Message.Content` When Lifting `Index` Off An Unrecognized Block

Reading `AIMessage.content_blocks` for a message with a non-standard Anthropic content block containing an `index` key silently deletes that key from the original `message.content` because the fallback branch pops `index` from the same dict object stored in the message. This also affects `model_provider="bedrock"` via bedrock.py importing the same function.

highConfidence 97%LangchainAffected V1.6.1

Origin Analysis

In `_convert_to_v1_from_anthropic`, the `else` branch for unrecognized block types wraps the original block dict by reference: `new_block["value"] = block` and then `new_block["value"].pop("index")`. Since `new_block["value"]` is the same object as `block`, the `pop` deletes `index` from the message's stored content, corrupting it as a side effect of accessing a property that appears read-only.
1. Create `message = AIMessage(content=[{'type':'custom','payload':'value','index':3}], response_metadata={'model_provider':'anthropic'})`.\n2. Make a deep copy of `message.content`.\n3. Access `message.content_blocks` once.\n4. Compare `message.content` to the deep copy: the `index` key has been removed from the original content dict.

Fixing Code Block

Edge Case Audit

Shallow copy only protects the top-level `index` key; if external code later mutates nested contents of the non-standard block, those nested objects are shared with the original message content. However, that is outside the scope of this fix. If a rollback is needed, revert this change to the previous mutation-prone version. Concurrency: the original block is no longer modified during conversion, so simultaneous reads of `.content_blocks` from multiple threads are safe. Upgrading to a fixed version is recommended; if patching manually, ensure both `anthropic` and `bedrock` code paths use the updated function.

Ecosystem Topology