Skip to content

adk_request_credential FunctionCall args contain non-JSON-serializable SecuritySchemeType enum #6006

Closed

Description

@doughayden

🔴 Required Information

Describe the Bug:

build_auth_request_event in src/google/adk/flows/llm_flows/functions.py builds the adk_request_credential (EUC) FunctionCall.args with AuthToolArguments(...).model_dump(exclude_none=True, by_alias=True). The default mode="python" leaves the auth scheme's type field as a live SecuritySchemeType enum member inside the args dict, rather than its string value. The resulting Event.content is therefore not JSON-serializable: any consumer that calls json.dumps on the in-memory event content raises TypeError: Object of type SecuritySchemeType is not JSON serializable.

This is latent for most flows because the session DB launders enums to strings on write (pydantic JSON serialization), and ADK's own auth preprocessor re-validates the args from either form. It surfaces for any consumer that serializes the in-memory event before it round-trips through the DB. A concrete trigger is memory ingestion: VertexAiMemoryBankService hands the in-memory event.content to the Vertex SDK, which json.dumps's it.

Steps to Reproduce:

Run the snippet below against google-adk 2.2.0. It performs the same model_dump call as build_auth_request_event and then the same json.dumps the Vertex SDK performs during memory ingestion.

import json
from google.adk.auth.auth_tool import AuthConfig, AuthToolArguments
from google.adk.auth.auth_credential import AuthCredential, AuthCredentialTypes, OAuth2Auth
from google.adk.auth.auth_schemes import OAuth2
from fastapi.openapi.models import OAuthFlows, OAuthFlowAuthorizationCode

scheme = OAuth2(flows=OAuthFlows(authorizationCode=OAuthFlowAuthorizationCode(
    authorizationUrl="https://example/authorize", tokenUrl="https://example/token", scopes={})))
cfg = AuthConfig(auth_scheme=scheme,
                 raw_auth_credential=AuthCredential(auth_type=AuthCredentialTypes.OAUTH2,
                                                    oauth2=OAuth2Auth(client_id="x", client_secret="y")))

# The exact dump build_auth_request_event performs (functions.py, default mode="python")
args = AuthToolArguments(function_call_id="abc", auth_config=cfg).model_dump(
    exclude_none=True, by_alias=True)
print(repr(args["authConfig"]["authScheme"]["type"]))  # <SecuritySchemeType.oauth2: 'oauth2'> — live enum
json.dumps(args)  # TypeError: Object of type SecuritySchemeType is not JSON serializable

# The fix: mode="json" coerces the enum to its string value, same dump otherwise
fixed = AuthToolArguments(function_call_id="abc", auth_config=cfg).model_dump(
    mode="json", exclude_none=True, by_alias=True)
print(repr(fixed["authConfig"]["authScheme"]["type"]))  # 'oauth2'
json.dumps(fixed)  # passes

Expected Behavior:

The adk_request_credential FunctionCall.args are JSON-serializable, consistent with how the same content is stored and re-read from the session DB. model_dump(mode="json", exclude_none=True, by_alias=True) coerces the enum to its "oauth2" string while preserving aliases; ADK's parse-back is unaffected because pydantic validation accepts the string form (exactly what it already does for DB-read events).

Observed Behavior:

json.dumps on the in-memory event content raises:

TypeError: Object of type SecuritySchemeType is not JSON serializable

In a real flow (memory ingest on the EUC turn) this surfaces as a background task failure:

ERROR vertex_ai_memory_bank_service.py | Background ingest_events task failed: Object of type SecuritySchemeType is not JSON serializable

Environment Details:

  • ADK Library Version (pip show google-adk): 2.2.0 (latest release; identical on main, the dump is at functions.py:305, SHA 9670ce2)
  • Desktop OS: macOS
  • Python Version (python -V): 3.13

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: N/A, the bug is in event construction and model-independent

🟡 Optional Information

Regression:

Not a recent regression. The python-mode dump has been in place across releases (present in the 1.x line and unchanged on the current 2.x main); it only becomes observable when a consumer serializes the in-memory EUC event before DB round-trip.

Logs:

TypeError: Object of type SecuritySchemeType is not JSON serializable

Additional Context:

Sibling call sites in the same file use the same python-mode model_dump and may carry the same hazard if their models contain enums (like the tool-confirmation args around functions.py:368/:371, and event.actions.model_dump(...) near line 1241). Worth a glance during the fix, but the auth-request path is the confirmed, reproducible one. Discovered downstream while validating an OAuth resume flow; the in-memory event reached json.dumps via memory ingestion before any DB round-trip.

Minimal Reproduction Code:

Inline in Steps to Reproduce above; self-contained against a clean pip install google-adk==2.2.0.

How often has this issue occurred?:

  • Always (100%), deterministic for any consumer that json.dumps's the in-memory EUC event content.

Activity

  1. added
    auth[Component] This issue is related to authorization
    on Jun 7, 2026
  2. added theissue type on Jun 7, 2026
  3. adk-bot commented on Jun 7, 2026

    @adk-bot
    Collaborator

    GitHub Issue #6006 Analysis: adk_request_credential FunctionCall args contain non-JSON-serializable SecuritySchemeType enum

    Executive Summary

    1. What is broken? Pydantic's default .model_dump() serialization uses mode="python", retaining nested SecuritySchemeType enums as live Python Enum objects in the dumped args dictionary, rather than serializing them to primitive strings. When downstream consumers (such as the Vertex AI SDK during memory ingestion) attempt to serialize these in-memory events via standard JSON methods (like json.dumps()), it raises a TypeError: Object of type SecuritySchemeType is not JSON serializable exception.
    2. Is there a linked PR that fixes this issue? None
    3. Recommendation: Should Fix (High Priority). This bug fails background tasks deterministicly (e.g. in VertexAiMemoryBankService) whenever an EUC turn auth-request occurs, blocking critical functionality. The fix is low risk and simply requires updating .model_dump() to use mode="json".
    Detailed Analysis

    1. Root Cause Analysis ("What is broken?")

    When an End User Credential (EUC) request is built to execute tools or toolset-level authentication, build_auth_request_event(...) is invoked to construct an authorization request with an adk_request_credential FunctionCall. Inside this function, the AuthToolArguments pydantic model is serialized to a dictionary via:

    AuthToolArguments(
        function_call_id=function_call_id,
        auth_config=auth_config,
    ).model_dump(exclude_none=True, by_alias=True)

    Because no Python-to-JSON serialization mode is specified, Pydantic defaults to mode="python". This preserves the nested SecuritySchemeType enum fields (the auth scheme's type field, such as SecuritySchemeType.oauth2) as live Python Enum members nested inside the returned dictionary.

    While the issue is usually hidden during round-tripping through standard databases (which deserialize JSON to string values, automatically "cleansing" the enum objects), it immediately surfaces when any consumer or SDK performs standard JSON serialization (such. as json.dumps) directly on the in-memory event content beforehand.

    A critical downstream failure occurs inside the VertexAiMemoryBankService background task ingest_events where the intact in-memory event.content containing the live SecuritySchemeType object is passed to the Vertex SDK, raising:
    TypeError: Object of type SecuritySchemeType is not JSON serializable

    Code References

    The failure resides in the following two core locations where AuthToolArguments are dumped without mode="json":

    • functions.py — Used in LLM Flows for building tool authentication request events.
    • _workflow_hitl_utils.py — Used in Workflows for constructing HITL authorization credential request events.

    Additionally, other sibling call sites of .model_dump are vulnerable to the same issue if they ever process nested Enum members:

    • functions.py — Used when dumping originalFunctionCall and toolConfirmation to construct tool confirmation requests.

    2. Existing Pull Requests ("Is there a linked PR that fixes this issue?")

    • Linked PR: None
    • PR URL: N/A
    • Analysis: A search of PRs using gh pr list --repo google/adk-python --search "6006" returned no matches. However, the root cause logic has been verified locally on the current main branch.

    3. Recommendation

    • Recommendation: Should Fix (High Priority)
    • Rationale:
      • User Impact: Greatly disrupts human-in-the-loop (HITL) and EUC authentication scenarios by causing background engine tasks to crash deterministically with uncaught type errors.
      • Implementation Complexity: Low. The fix is extremely safe. Changing the dump logic to use Pydantic V2's mode="json" natively coerces nested enums into their target JSON strings while remaining fully backward-compatible with ADK's internal parsers (which safely validate enum strings back to enum members).
      • Proposed Fix Code Outline:
        # In src/google/adk/flows/llm_flows/functions.py (Line 305):
        ).model_dump(mode="json", exclude_none=True, by_alias=True)
        
        # In src/google/adk/workflow/utils/_workflow_hitl_utils.py (Line 175):
        ).model_dump(mode="json", exclude_none=True, by_alias=True)
        
        # In src/google/adk/flows/llm_flows/functions.py (Lines 368 & 371):
        'originalFunctionCall': original_function_call.model_dump(
            mode="json", exclude_none=True, by_alias=True
        ),
        'toolConfirmation': tool_confirmation.model_dump(
            mode="json", by_alias=True, exclude_none=True
        ),

    Next Steps & Summary of Work

    I analyzed GitHub Issue #6006, mapped down all root extraction failure points including functions.py and external workflow counterparts, verified that no linked PRs currently exist, and provided a comprehensive architectural fix.

    Please let me know if you would like me to proceed with implementing the fixes and verifying the tests!

  4. surajksharma07 commented on Jun 8, 2026

    @surajksharma07
    Collaborator

    @doughayden As a quick workaround, try swapping the .model_dump() at functions.py:305 (and the matching call in _workflow_hitl_utils.py) to use mode="json" — i.e. .model_dump(mode="json", exclude_none=True, by_alias=True) — and verify that json.dumps(args) no longer raises in your OAuth EUC flow.

    If this resolves the memory ingestion crash on your end, please run the full test suite and confirm everything passes before pushing the PR — want to make sure the parse-back path (enum string → enum member via Pydantic validation) holds up end-to-end.

    Happy to take a look once you've confirmed it's solid!

  5. added
    request clarification[Status] The maintainer need clarification or more information from the author
    v2Affects only 2.0 version
    on Jun 8, 2026
  6. added a commit that references this issue on Jun 8, 2026
    c607d36
  7. doughayden commented on Jun 8, 2026

    @doughayden
    ContributorAuthor

    @surajksharma07 thanks for the workaround confirmation. I opened #6007 a day ago with exactly that mode="json" fix, and following your note I've expanded it to the second call site: create_auth_request_event in workflow/utils/_workflow_hitl_utils.py, the v2 workflow HITL path. Both auth-request builders now dump with mode="json", each with a regression test.

    On the memory ingestion crash: confirmed resolved on our end. We originally hit this exact failure through VertexAiMemoryBankService ingest (Object of type SecuritySchemeType is not JSON serializable). Re-running our OAuth EUC flow today with the mode="json" fix in place, the post-resume ingest completed clean: no serialization error and zero errors in the log window. In our deployment the in-memory event that ingest serializes comes from our own resume-message builder, so that's where we observe the real-world fix, but it's the identical bug pattern this PR clears in ADK's builders. I verified the PR's exact change against current main with the inline json.dumps repro from the issue.

    Full unit suite is green locally, including the two new regression tests (each fails before its change, passes after). PR is ready for review whenever you have a chance.

  8. surajksharma07 commented on Jun 11, 2026

    @surajksharma07
    Collaborator

    @doughayden Thanks for folding in the workflow HITL path and confirming the ingest fix on a real OAuth EUC run — went through the updated #6007 and both builders now dump json-mode, with the regression tests sitting at exactly the right boundary. Nice that the LLM-flow one exercises the full runner path.

    On the siblings: I'd keep them out of this PR. The tool-confirmation args at functions.py:368 share the same hazard surface — long-running function_call.args that memory ingest can serialize — so that's worth its own issue with a repro.

    The actions dump near :1241 is an internal merge that gets re-validated into EventActions and never crosses a json.dumps boundary, so python-mode is fine there.

    Nothing blocking from my side — PR's in review now!

    Team is looking more into it.
    Thanks!

  9. doughayden commented on Jun 11, 2026

    @doughayden
    ContributorAuthor

    Thanks @surajksharma07, sounds good! I'm happy to open a separate PR for those siblings if you feel the team would value that contribution. I'll refer to this issue in a fresh PR without creating a separate companion issue if that's easier/preferred.

  10. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    and removed
    request clarification[Status] The maintainer need clarification or more information from the author
    on Jun 11, 2026
  11. surajksharma07 commented on Jun 16, 2026

    @surajksharma07
    Collaborator

    @doughayden Good catch, and that's on us, not you — check-file-contents.yml's googleapis.com/mTLS check scans the full file content of anything you touch, not just your diff.

    Unlike the import-pattern/cli-import checks right above it in that same workflow, it never got a tests/.* exclusion, so the other 20 pre-existing fixtures get swept in just because you added two lines to that file.

    Leave them alone — rewriting fixtures you didn't author is out of scope for a one-line serialization fix.

    I'll get the workflow patched to add the same tests/.* exclusion its siblings already have and merge once review is otherwise green.

    No need to touch test_functions_request_euc.py beyond your two lines!

  12. doughayden commented on Jun 16, 2026

    @doughayden
    ContributorAuthor

    Thanks @surajksharma07, makes sense. I'll leave the fixtures for your workflow patch then and won't push anything further.

  13. added a commit that references this issue on Jun 17, 2026
    a181a39
  14. added a commit that references this issue on Aug 11, 2026
    6dc9b8f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

auth[Component] This issue is related to authorizationneeds review[Status] The PR/issue is awaiting review from the maintainerv2Affects only 2.0 version

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions