litellm - 💡(How to fix) Fix tool_registry_writer: batch_upsert_tools passes text to timestamp column via .isoformat() [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#25392Fetched 2026-04-10 03:41:22
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Participants

Error Message

ERROR: column "created_at" is of type timestamp without time zone but expression is of type text

Fix Action

Fix

Remove .isoformat() and pass the datetime object directly. Prisma's raw query engine handles datetimetimestamp conversion natively:

now = datetime.now(timezone.utc)  # not .isoformat()

The same pattern exists in update_tool_policy (line ~145 on main).

Code Example

now = datetime.now(timezone.utc).isoformat()
await prisma_client.db.execute_raw(
    'INSERT INTO "LiteLLM_ToolTable" '
    "(tool_id, tool_name, origin, call_policy, call_count, created_by, updated_by, key_hash, team_id, key_alias, created_at, updated_at) "
    "VALUES ($7, $1, $2, 'untrusted', 1, $3, $3, $4, $5, $6, $8, $8) "
    "ON CONFLICT ...",
    ..., now,
)

---

ERROR: column "created_at" is of type timestamp without time zone but expression is of type text

---

now = datetime.now(timezone.utc)  # not .isoformat()
RAW_BUFFERClick to expand / collapse

Bug

batch_upsert_tools in litellm/proxy/db/tool_registry_writer.py calls datetime.now(timezone.utc).isoformat() and passes the resulting string as a parameter to execute_raw:

now = datetime.now(timezone.utc).isoformat()
await prisma_client.db.execute_raw(
    'INSERT INTO "LiteLLM_ToolTable" '
    "(tool_id, tool_name, origin, call_policy, call_count, created_by, updated_by, key_hash, team_id, key_alias, created_at, updated_at) "
    "VALUES ($7, $1, $2, 'untrusted', 1, $3, $3, $4, $5, $6, $8, $8) "
    "ON CONFLICT ...",
    ..., now,
)

Since now is a Python string (from .isoformat()), Prisma's raw query engine sends it as text. PostgreSQL rejects it:

ERROR: column "created_at" is of type timestamp without time zone but expression is of type text

This fires on every tool registry sync cycle (~204 times/hour), producing ~5K error log lines per day.

Environment

  • LiteLLM version: v1.82.0-stable (also reproduced by reading main branch code — same pattern exists)
  • PostgreSQL (via Prisma)
  • Prisma schema defines created_at DateTime @default(now())

Fix

Remove .isoformat() and pass the datetime object directly. Prisma's raw query engine handles datetimetimestamp conversion natively:

now = datetime.now(timezone.utc)  # not .isoformat()

The same pattern exists in update_tool_policy (line ~145 on main).

extent analysis

TL;DR

Remove the .isoformat() call when generating the now variable to allow Prisma's raw query engine to handle the datetime object conversion to timestamp natively.

Guidance

  • Identify all occurrences of datetime.now(timezone.utc).isoformat() in the codebase, particularly in tool_registry_writer.py, and remove the .isoformat() call to pass the datetime object directly.
  • Verify that the created_at and updated_at columns in the PostgreSQL database are of type timestamp without time zone to ensure compatibility with Prisma's native datetime to timestamp conversion.
  • Review the Prisma schema to confirm that the created_at field is defined with the @default(now()) directive, ensuring that the current timestamp is used when inserting new records.
  • Test the updated code to confirm that the error log lines related to the column "created_at" is of type timestamp without time zone but expression is of type text error have decreased significantly.

Example

now = datetime.now(timezone.utc)  # Remove .isoformat()
await prisma_client.db.execute_raw(
    'INSERT INTO "LiteLLM_ToolTable" '
    "(tool_id, tool_name, origin, call_policy, call_count, created_by, updated_by, key_hash, team_id, key_alias, created_at, updated_at) "
    "VALUES ($7, $1, $2, 'untrusted', 1, $3, $3, $4, $5, $6, $8, $8) "
    "ON CONFLICT ...",
    ..., now,
)

Notes

This fix assumes that the Prisma version being used supports native datetime to timestamp conversion. If issues persist, verify the Prisma version and consult the relevant documentation.

Recommendation

Apply the workaround by removing the .isoformat() call and passing the datetime object directly, as this allows Prisma's raw query engine to handle the conversion natively and resolves the error.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING