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

Merge_message_runs Is O(N^2) In Run Length For List/Content-Block Messages

Merging consecutive same-type messages with list content blocks re-validates the growing message on every step, causing quadratic runtime and freezing on long runs.

highConfidence 92%Langchain-CoreAffected V1.4.7

Origin Analysis

merge_message_runs folds a run pairwise, converting the accumulator to a chunk and back each iteration, so Pydantic SchemaSerializer.to_python and SchemaValidator.validate_python are invoked on the entire accumulated content every step.
```python import time from langchain_core.messages import HumanMessage from langchain_core.messages.utils import merge_message_runs for n in (500, 1000, 2000, 4000): msgs = [HumanMessage([{"type": "text", "text": f"m{i}"}]) for i in range(n)] start = time.perf_counter() merge_message_runs(msgs) print(n, round(time.perf_counter() - start, 3), "s") ``` Expected output shows runtime growing roughly quadratically.

Fixing Code Block

Edge Case Audit

The fix preserves non-content fields from the first message of each run. If consecutive same-type messages have differing metadata (e.g., AIMessage tool_calls, response_metadata), this implementation does not merge those fields, which may differ from the previous behavior if such merging was implicitly supported. Test with AIMessage runs containing tool_calls before deploying. Rollback is straightforward: restore the previous pairwise merge implementation. Additionally, Pydantic validation still occurs once per run; for extremely large content lists this validation is linear but can be noticeable, so consider chunking or avoiding merge for massive histories.

Ecosystem Topology