Skip to content

fix(sessions): truncate error_message in v0 StorageEvent to guard against VARCHAR(255) overflow#5020

Open
STHITAPRAJNAS wants to merge 2 commits intogoogle:mainfrom
STHITAPRAJNAS:fix/db-error-message-truncation-4993
Open

fix(sessions): truncate error_message in v0 StorageEvent to guard against VARCHAR(255) overflow#5020
STHITAPRAJNAS wants to merge 2 commits intogoogle:mainfrom
STHITAPRAJNAS:fix/db-error-message-truncation-4993

Conversation

@STHITAPRAJNAS
Copy link
Copy Markdown

Fixes #4993.

Problem

DatabaseSessionService crashes on PostgreSQL databases that were created with an older ADK version where error_message was a VARCHAR(255) column. create_all() is additive-only — it never ALTERs existing columns — so those databases keep the narrow column indefinitely even after upgrading the package.

When a model returns a MALFORMED_FUNCTION_CALL error whose payload echoes back a large JSON body, the unbounded error_message string exceeds 255 characters and hits:

asyncpg.exceptions.StringDataRightTruncationError: value too long for type character varying(255)

This terminates the SSE stream entirely with no fallback and no warning to the caller.

Fix

Add a write-path guard in StorageEvent.from_event() (v0 schema only). If error_message exceeds the legacy column width it is clipped to 241 characters and suffixed with "...[truncated]", keeping the total at exactly 255. Messages within the limit are passed through unchanged.

The guard lives in the schema layer rather than the service layer so it is applied regardless of the call site, and it is scoped to v0 only because v1 stores everything in a JSONB event_data column and is not affected.

Two constants are introduced at module level with a comment explaining the invariant, so the magic number is traceable without digging into the issue history.

Permanent fix

Users on PostgreSQL with a legacy schema can resolve this at the DB level with:

ALTER TABLE events ALTER COLUMN error_message TYPE TEXT;

Or migrate to v1 fully via adk migrate session.

Testing

Added two unit tests to test_v0_storage_event.py:

  • test_from_event_truncates_error_message_exceeding_varchar255 — a 300-char message is clamped to ≤ 255 chars and ends with the truncation suffix
  • test_from_event_preserves_short_error_message — a short message is stored verbatim

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Mar 27, 2026
Copy link
Copy Markdown

@JiwaniZakir JiwaniZakir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test test_from_event_truncates_error_message_exceeding_varchar255 asserts len(...) <= _LEGACY_ERROR_MSG_MAX_LEN, but given the deterministic truncation logic in from_event, this should be a strict equality check (== _LEGACY_ERROR_MSG_MAX_LEN) — the weaker assertion would pass even if the truncation were accidentally off by several characters. There's also no test case for error_message=None, which exercises the falsy branch of the condition in from_event; while the logic looks correct, an explicit test would document the intent and prevent regressions. Additionally, the test file imports the private symbols _LEGACY_ERROR_MSG_MAX_LEN and _TRUNCATION_SUFFIX directly — if these ever need to be refactored or inlined, the test becomes a coupling point; consider asserting the concrete expected string ("x" * 241 + "...[truncated]") or at least the exact final length (255) to reduce that dependency.

@STHITAPRAJNAS
Copy link
Copy Markdown
Author

Thanks for the thorough review @JiwaniZakir — all three points are valid, addressed in 9353950:

  • Strict equality: changed <= _LEGACY_ERROR_MSG_MAX_LEN to == "x" * 241 + "...[truncated]" — the full concrete expected string, which also removes the need for the private symbol import
  • Private symbol coupling: dropped the _LEGACY_ERROR_MSG_MAX_LEN and _TRUNCATION_SUFFIX imports; the test now asserts the exact output string directly
  • None branch: added test_from_event_with_none_error_message to document and protect the falsy path through the guard

…inst VARCHAR(255) overflow

Databases created with earlier ADK versions retain error_message as
VARCHAR(255) because create_all() is additive-only and never ALTERs
existing columns. When a model returns a MALFORMED_FUNCTION_CALL error
with a large JSON payload, the unbounded error_message silently exceeds
that limit and raises StringDataRightTruncationError, terminating the
SSE stream with no fallback.

The fix adds a write-path guard in StorageEvent.from_event(): if the
message exceeds 255 characters it is clipped to 241 chars and suffixed
with "...[truncated]", keeping the total within the legacy column width.
Messages within the limit are passed through unchanged. The v1 schema is
unaffected (error_message is stored inside the event_data JSONB column).

The permanent fix remains running:
  ALTER TABLE events ALTER COLUMN error_message TYPE TEXT;
or migrating to the v1 schema via `adk migrate session`.

Fixes google#4993
…view

- Replace <= with == in the truncation test: the guard is deterministic
  so the result should be exactly 255 chars, not merely at most 255
- Assert the concrete expected string ("x" * 241 + "...[truncated]")
  rather than importing private module symbols, reducing coupling to
  internal implementation details
- Add test_from_event_with_none_error_message to cover the falsy branch
  of the truncation condition and document that None passes through
  unchanged
@STHITAPRAJNAS STHITAPRAJNAS force-pushed the fix/db-error-message-truncation-4993 branch from 9353950 to a6e3d89 Compare March 27, 2026 15:37
@rohityan rohityan self-assigned this Mar 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] DatabaseSessionService (v0 schema): StringDataRightTruncationError on PostgreSQL when error_message exceeds VARCHAR(255)

4 participants