temporal-spring-ai: guard large media byte[] from entering workflow history#2860
Merged
donald-pinckney merged 5 commits intomasterfrom Apr 23, 2026
Merged
temporal-spring-ai: guard large media byte[] from entering workflow history#2860donald-pinckney merged 5 commits intomasterfrom
donald-pinckney merged 5 commits intomasterfrom
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…istory ChatModelTypes.checkMediaSize() rejects Media byte[] payloads larger than 1 MiB (default, overridable via the 'io.temporal.springai.maxMediaBytes' system property) with a non-retryable ApplicationFailure pointing users at the URI-based Media constructor. ActivityChatModel.toMediaContent and ChatModelActivityImpl.fromMedia call the guard on both directions of the activity boundary. The guard throws a non-retryable ApplicationFailure — not a plain IllegalArgumentException — because this is a permanent, programmer-level error. Throwing a RuntimeException would cause the workflow task to be retried forever (or the activity to churn through its maxAttempts) rather than surfacing the real problem. README gains a "Media in messages" section documenting the cap, the override property, and the URI alternative. Tests: MediaSizeGuardTest covers the helper directly (unit), plus inbound/outbound activity-boundary paths via TestWorkflowEnvironment: - oversized user-message media fails the workflow with the guard error - small media passes through - URI-based media passes regardless of would-be size - assistant-echoed oversized media fails the activity Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Planning scratchpad — not part of the shipped artifact. Removed before merge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
brianstrauch
approved these changes
Apr 23, 2026
mjameswh
approved these changes
Apr 23, 2026
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.
What was changed
ChatModelTypes.checkMediaSize(byte[])— new helper that throws a non-retryableApplicationFailure(failure type"MediaSizeExceeded") when aMedia.databyte array exceeds theMAX_MEDIA_BYTES_IN_HISTORYthreshold (default 1 MiB, overridable with theio.temporal.springai.maxMediaBytessystem property;0disables).ActivityChatModel.toMediaContent(...)andChatModelActivityImpl.fromMedia(...)call the guard on both directions of the activity boundary so oversized payloads are rejected at the point of serialization instead of deep inside a gRPC failure.MediaSizeGuardTest— unit tests on the helper plus integration tests usingTestWorkflowEnvironmentthat verify (1) oversizedUserMessagemedia fails the workflow with the guard error, (2) small media passes, (3) URI-based media passes regardless of would-be size, and (4) assistant-echoed oversized media fails the activity on the return path.Why?
Raw media bytes on
UserMessage/AssistantMessageget serialized into every relevant history event. Temporal's default per-event payload limit is 2 MiB; a single 5 MB PNG silently produces a cryptic gRPC failure at workflow runtime. Failing fast at the serialization edge, with a non-retryableApplicationFailurewhose message points at the URI-based constructor, turns a mystery failure into an obvious fix.The guard uses a non-retryable
ApplicationFailureinstead ofIllegalArgumentExceptionso it fails the workflow / activity immediately rather than triggering indefinite workflow-task retries. This is a permanent, programmer-level error; retrying the same oversized payload will never succeed.