Skip to content

fix(memory): jsonify metadata before Prisma writes on /v1/memory#26536

Merged
krrish-berri-2 merged 3 commits into
litellm_internal_stagingfrom
litellm_memory_improvements_v2
Apr 26, 2026
Merged

fix(memory): jsonify metadata before Prisma writes on /v1/memory#26536
krrish-berri-2 merged 3 commits into
litellm_internal_stagingfrom
litellm_memory_improvements_v2

Conversation

@krrish-berri-2

@krrish-berri-2 krrish-berri-2 commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

The POST/PUT memory endpoints handed bare dicts (and bare None) to prisma-client-python for the Json? metadata column, which the client rejects with MissingRequiredValueError / DataError: metadata should be of any of the following types: NullableJsonNullValueInput, Json. All write paths (POST, PUT-update, PUT-create) now route metadata through a dedicated _serialize_metadata_for_prisma helper that always json.dumps the payload — covering every Optional[Any] shape (dict, list, scalar, plain string), all of which Postgres jsonb requires to be valid JSON.

Explicit metadata: null on PUT is encoded as JSON null (Postgres jsonb 'null') — prisma-client-python has no JsonNull/DbNull sentinel for writing a true SQL NULL (RobertCraigie/prisma-client-py#714), but the typed client deserializes jsonb 'null' back to Python None on read, so from a caller's perspective PUT {"metadata": null} clears the field. Callers wanting a strict SQL NULL must use raw SQL — there is no typed-client path.

The POST/PUT memory endpoints handed bare dicts (and bare `None`) to
prisma-client-python for the `Json?` `metadata` column, which the client
rejects with `MissingRequiredValueError` / `DataError: metadata should
be of any of the following types: NullableJsonNullValueInput, Json`.
Both the create and upsert paths now route writes through the existing
`jsonify_object` helper used elsewhere in the proxy for `Json?` columns
(e.g. `LiteLLM_VerificationToken.budget_limits`), and omit metadata
when None so the column defaults to SQL NULL via the schema.

Explicit `metadata: null` on PUT is now a no-op for the column to match
how the rest of the proxy handles nullable JSON fields (no
`JsonNull`/`DbNull` sentinel exists in prisma-client-python — see
RobertCraigie/prisma-client-py#714). A payload with only `metadata: null`
returns 400 instead of a misleading 200.

Made-with: Cursor
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps

greptile-apps Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a DataError / MissingRequiredValueError raised by prisma-client-python when raw Python values (dicts, lists, scalars, None) were passed directly to the Json? metadata column on POST /v1/memory and PUT /v1/memory/{key}. The fix introduces a dedicated _serialize_metadata_for_prisma helper that unconditionally calls json.dumps, handling all metadata types correctly and replacing the previous jsonify_object approach.

Confidence Score: 4/5

Safe to merge with the caveat that metadata: null on PUT is now a documented no-op rather than a field-clear, which is a backwards-incompatible behaviour change noted in previous review threads.

The core serialisation fix is correct and well-tested across all metadata types (dict, list, scalar, string). No new P0/P1 issues were found in this review pass. The backwards-incompatible metadata: null behaviour from prior threads is still unresolved but documented in the PR description; it holds the ceiling at 4/5.

No files require special attention beyond the stale jsonify_object comment in the test mock.

Important Files Changed

Filename Overview
litellm/proxy/memory/memory_endpoints.py Introduces _serialize_metadata_for_prisma (always json.dumps) to fix Prisma DataError on Json? columns; applied consistently across POST create, PUT update, and PUT-create paths. The metadata: null no-op behaviour is a documented backwards-incompatible change (flagged separately in previous review threads).
tests/test_litellm/proxy/memory/test_memory_endpoints.py Good test coverage added for dict/list/string/scalar metadata serialization and null-only 400 path. Mock create/update helpers now round-trip JSON correctly. Stale jsonify_object references in mock comments should be updated to _serialize_metadata_for_prisma.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["POST /v1/memory or PUT /v1/memory/{key}"] --> B{body.metadata is None?}
    B -- Yes --> C[Omit metadata field\ncolumn defaults to SQL NULL]
    B -- No --> D["_serialize_metadata_for_prisma(metadata)\njson.dumps → str"]
    D --> E{PUT: existing row?}
    C --> E
    E -- Yes/Update --> F[prisma .update with data dict]
    E -- No/Create --> G[prisma .create with create_data dict]
    F --> H[Return LiteLLM_MemoryRow]
    G --> H
    B2{metadata: null AND\nonly field sent?} -- Yes --> I[HTTP 400]
Loading

Reviews (3): Last reviewed commit: "fix(memory): always json.dumps metadata,..." | Re-trigger Greptile

Comment thread litellm/proxy/memory/memory_endpoints.py Outdated
Comment thread litellm/proxy/memory/memory_endpoints.py
`jsonify_object` only stringifies dict values, so list-shaped metadata
still hit Prisma as raw Python objects and triggered the same
DataError this PR is meant to fix. `metadata` is typed `Optional[Any]`
so list payloads are valid input. Replace `jsonify_object` with a
local `_serialize_metadata_for_prisma` helper that always `json.dumps`
non-string values, applied at all three write sites
(POST create, PUT update, PUT-create). Adds regression tests for
list metadata on each path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread litellm/proxy/memory/memory_endpoints.py
The str-passthrough in `_serialize_metadata_for_prisma` left plain
Python strings (e.g. `metadata: "hello"`) unencoded — Postgres `jsonb`
rejects bare-word strings as invalid JSON, reproducing the same
DataError this PR is meant to fix. Always `json.dumps` regardless of
input type so all `Optional[Any]` shapes (dict, list, scalar, str)
become valid JSON. Adds a regression test for plain-string metadata.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Apr 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 25.00000% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/proxy/memory/memory_endpoints.py 25.00% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@krrish-berri-2 krrish-berri-2 merged commit 740bb44 into litellm_internal_staging Apr 26, 2026
115 of 116 checks passed
@krrish-berri-2 krrish-berri-2 deleted the litellm_memory_improvements_v2 branch April 26, 2026 01:26
Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request Apr 26, 2026
hunterchris pushed a commit to hunterchris/litellm that referenced this pull request Apr 27, 2026
…riAI#26536)

* fix(memory): jsonify metadata before Prisma writes on /v1/memory

The POST/PUT memory endpoints handed bare dicts (and bare `None`) to
prisma-client-python for the `Json?` `metadata` column, which the client
rejects with `MissingRequiredValueError` / `DataError: metadata should
be of any of the following types: NullableJsonNullValueInput, Json`.
Both the create and upsert paths now route writes through the existing
`jsonify_object` helper used elsewhere in the proxy for `Json?` columns
(e.g. `LiteLLM_VerificationToken.budget_limits`), and omit metadata
when None so the column defaults to SQL NULL via the schema.

Explicit `metadata: null` on PUT is now a no-op for the column to match
how the rest of the proxy handles nullable JSON fields (no
`JsonNull`/`DbNull` sentinel exists in prisma-client-python — see
RobertCraigie/prisma-client-py#714). A payload with only `metadata: null`
returns 400 instead of a misleading 200.

Made-with: Cursor

* fix(memory): JSON-encode non-dict metadata before Prisma writes

`jsonify_object` only stringifies dict values, so list-shaped metadata
still hit Prisma as raw Python objects and triggered the same
DataError this PR is meant to fix. `metadata` is typed `Optional[Any]`
so list payloads are valid input. Replace `jsonify_object` with a
local `_serialize_metadata_for_prisma` helper that always `json.dumps`
non-string values, applied at all three write sites
(POST create, PUT update, PUT-create). Adds regression tests for
list metadata on each path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(memory): always json.dumps metadata, not just non-strings

The str-passthrough in `_serialize_metadata_for_prisma` left plain
Python strings (e.g. `metadata: "hello"`) unencoded — Postgres `jsonb`
rejects bare-word strings as invalid JSON, reproducing the same
DataError this PR is meant to fix. Always `json.dumps` regardless of
input type so all `Optional[Any]` shapes (dict, list, scalar, str)
become valid JSON. Adds a regression test for plain-string metadata.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants