Repository navigation
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
wahllllll
force-pushed
the
fix/json-codec-read-constraints
branch
from
October 10, 2026 01:58
39d84ae to
1e0171a
Compare
Jackson's default StreamReadConstraints reject any single string value above 20,000,000 characters on read, while serialization imposes no cap at all. Every AgentStateStore -- JSON file, JDBC, Redis, MongoDB, OSS, COS, the Service JPA store -- persists through JsonUtils.getJsonCodec(), i.e. this codec's default ObjectMapper, and an AgentState carrying inline Base64 media (a 25 MB video is 33.5 million characters) saved successfully and then failed to load on the very next turn. Because the load happens before the model is called, every later turn of that session failed too, text-only ones included: a session bricked by its own persisted state. Configure the default ObjectMapper's JsonFactory with maxStringLength set to Integer.MAX_VALUE so the reader accepts whatever the writer emitted. Nesting depth, number length and name length keep their Jackson defaults; a caller- supplied ObjectMapper is left untouched. Strings this large only ever reach the codec from the framework's own persisted state -- model output and tool arguments are bounded far below the old limit -- so no untrusted boundary loses protection. Offloading media out of AgentState (agentscope-ai#2867) remains the right long-term answer; this restores the round-trip invariant the stores already rely on. Fixes agentscope-ai#3465
wahllllll
force-pushed
the
fix/json-codec-read-constraints
branch
from
October 10, 2026 02:37
1e0171a to
d853f25
Compare
Contributor
Author
|
The
Supporting evidence:
Nothing in this diff touches the failing paths. I'm happy to re-run again, but given |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
An
AgentStatecarrying inline Base64 media (the report's case: a 25 MBVideoBlock, 33,563,888 Base64 characters) saves successfully and then cannot be loaded. The load happens before the model is called, so every later turn of that session fails too — text-only turns included. The session is bricked by its own persisted state.Reported in #3465 against
OssAgentStateStore, with a standalone repro that needs no OSS, video or model.Root cause
The store is not where the bug lives. Every
AgentStateStore— JSON file, JDBC, Redis (Jedis/Redisson), MongoDB, OSS, COS and the Service JPA store — persists throughJsonUtils.getJsonCodec(), i.e. the single defaultJacksonJsonCodec. ItscreateDefaultObjectMapper()is a barenew ObjectMapper(), so it inherits Jackson's defaultStreamReadConstraints: a single string value may not exceed 20,000,000 characters on read. Serialization has no such cap.That is a round-trip asymmetry inside one codec:
toJsonaccepts a state that the same codec'sfromJsonrejects withA Base64 payload crosses 20 M characters at ~15 MB of source bytes; an OpenAI-size image limit (20 MB) already does.
Fix
Build the default
ObjectMapperfrom aJsonFactorywhose read constraints setmaxStringLengthtoInteger.MAX_VALUE, so the reader accepts whatever the writer emitted. Nesting depth, number length and name length keep their Jackson defaults, and a caller-suppliedObjectMapper(new JacksonJsonCodec(mapper)) is left untouched — only the framework's own default changes.Why the reader cap, not the writer
Jackson's read cap exists to bound memory from hostile input. Strings of this size only ever reach this codec from the framework's own persisted state: model output and tool arguments are bounded by provider output limits (well under 1 M characters), and HTTP bodies are bounded at the transport layer. So lifting the per-string cap on the default codec does not weaken an untrusted boundary — it removes a limit that only ever fired on data the framework itself wrote. Any finite ceiling below what
toJsoncan emit re-creates the asymmetry for the next larger payload; if you would rather keep one, the single number to change is increateDefaultObjectMapper().Offloading media out of
AgentState(#2867) remains the right long-term answer; this PR restores the round-trip invariant the stores already rely on today.Tests
Added
roundTripsStringsLongerThanJacksonDefaultReadLimittoJacksonJsonCodecTest: a 20,000,001-character string (one over the old cap) throughtoJson→fromJson, compared back.Red — on current
main:Green — with the fix:
spotless:applyapplied. No configuration change and no database migration.Fixes #3465