fix: cast ISO timestamp strings to timestamp type in tool_registry_writer SQL - #23449
fix: cast ISO timestamp strings to timestamp type in tool_registry_writer SQL#23449dkindlund wants to merge 1 commit into
Conversation
…iter SQL The raw SQL upserts in batch_upsert_tools and update_tool_policy pass datetime.isoformat() strings for created_at/updated_at columns. Prisma execute_raw treats these as text parameters, but PostgreSQL columns are timestamp without time zone and refuse implicit text-to-timestamp casts. Adds explicit ::timestamp casts to all timestamp parameter references. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes a real, actively-occurring production error (
Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| litellm/proxy/db/tool_registry_writer.py | Adds ::timestamp casts to all raw SQL timestamp parameter references in batch_upsert_tools and update_tool_policy to fix a PostgreSQL type mismatch. The fix is correct and targeted; a minor consideration is that ::timestamp silently strips timezone offset info from ISO strings, which is only safe here because the source is always timezone.utc. |
Sequence Diagram
sequenceDiagram
participant TD as Tool Discovery
participant TRW as tool_registry_writer
participant Prisma as Prisma execute_raw
participant PG as PostgreSQL
TD->>TRW: batch_upsert_tools(items)
TRW->>TRW: now = datetime.now(UTC).isoformat()
Note over TRW: e.g. "2026-03-12T13:34:30+00:00"
TRW->>Prisma: execute_raw(SQL, ..., now)
Note over Prisma: Binds now as text parameter $8
alt Before fix
Prisma->>PG: INSERT ... VALUES ($8, $8)<br/>[text → timestamp column]
PG-->>Prisma: ERROR: column is of type timestamp<br/>but expression is of type text
Prisma-->>TRW: Exception
TRW-->>TD: logs error, silently continues
else After fix
Prisma->>PG: INSERT ... VALUES ($8::timestamp, $8::timestamp)<br/>[explicit cast strips timezone offset]
PG-->>Prisma: OK (1 row upserted)
Prisma-->>TRW: success
TRW-->>TD: logs upserted N tool(s)
end
Comments Outside Diff (1)
-
litellm/proxy/db/tool_registry_writer.py, line 65-69 (link)Silent timezone truncation with
::timestampcastdatetime.now(timezone.utc).isoformat()produces a timezone-aware string like"2026-03-12T13:34:30.123456+00:00". When PostgreSQL casts this via::timestamp(without timezone), it silently strips the+00:00offset rather than converting from UTC — the stored wall-clock time equals the UTC time only because the source is alreadytimezone.utc. If this call-site ever changes to use a non-UTC local time, the offset would be silently discarded and wrong timestamps would be stored with no error.A more robust alternative is to pass a timezone-naive UTC
datetimedirectly (skipping.isoformat()), which avoids the ambiguity entirely:now = datetime.now(timezone.utc).replace(tzinfo=None) # naive UTC datetime
Or, if Prisma's
execute_rawhandles Pythondatetimeobjects (which Prisma typically does), you could drop the cast and use the object directly. Either approach makes the intent explicit and avoids silent timezone truncation.The same consideration applies to
update_tool_policyat line 143.
Last reviewed commit: 56252e2
|
Closing this PR — the fix was already applied on main via commit 291e6e1, which reverted the raw SQL approach back to Prisma ORM upserts (passing native datetime objects instead of .isoformat() strings). My local origin/main was stale when I created this branch. Apologies for the noise. |
Summary
Fixes
tool_registry_writer batch_upsert_tools error: ERROR: column "created_at" is of type timestamp without time zone but expression is of type textby adding explicit::timestampcasts to raw SQL parameter references.Steps to Reproduce
1. Deploy LiteLLM v1.82.0-stable with a PostgreSQL database and MCP/tool-calling enabled.
2. Send any request that triggers tool discovery (e.g., a chat completion with tool use).
3. The
tool_registry_writerbackground job fires and fails continuously:This error fires every ~8 seconds for as long as the proxy is running.
Production Evidence
Observed on Google Cloud Run deployment (
litellmservice,trending-threatsproject) running v1.82.0-stable with Cloud SQL PostgreSQL. 185 errors in a 1-hour window:Root Cause
The
batch_upsert_tools()andupdate_tool_policy()functions intool_registry_writer.pyuseexecute_raw()with ISO 8601 timestamp strings (datetime.now(timezone.utc).isoformat()):Prisma's
execute_raw()passes the.isoformat()string as atextparameter. PostgreSQL'screated_atandupdated_atcolumns aretimestamp without time zone, and PostgreSQL does not implicitly casttexttotimestampin parameterized queries.Fix
Added explicit
::timestampcasts to all timestamp parameter references in the raw SQL:Applied to both
batch_upsert_tools()andupdate_tool_policy().Test plan
::timestampcaststimestamp without time zonein PostgreSQLbatch_upsert_tools,update_tool_policy) are fixed