Skip to content

Python: key Chroma records by storage name when serializing and deserializing - #14763

Open
MOHAMMED WASIM KHAN (wasim-builds) wants to merge 1 commit into
microsoft:mainfrom
wasim-builds:fix/chroma-storage-name-record-keys
Open

MOHAMMED WASIM KHAN (wasim-builds) wants to merge 1 commit into
microsoft:mainfrom
wasim-builds:fix/chroma-storage-name-record-keys

Conversation

@wasim-builds

Copy link
Copy Markdown
Contributor

Motivation and Context

Closes #14755.

Dict and dataclass records reach the Chroma serializer keyed by storage name and pydantic models keyed by field name. The serializer read the key by declared name and the vector by storage name, so a dict or dataclass record with a storage_name on the key field failed to upsert and a pydantic model with a storage_name on the vector field failed too. The deserializer returned the key and the vector under the declared names, which the data model step does not read for dict and dataclass records, so a vector with a storage_name came back as None. Pydantic metadata was stored under the declared names, so filters on storage names did not match it.

Description

  • _serialize_dicts_to_store_models renames declared names to storage names in a copy of the record (only when the storage name is not already present), and then reads the key and vector by storage name.
  • _deserialize_store_models_to_dicts returns the key and vector under their storage names. The data model step maps them back for pydantic records.
  • Added comprehensive unit tests to tests/unit/connectors/memory/test_chroma.py (dict, dataclass, and pydantic, each with and without key storage_name). All 26 tests in test_chroma.py pass cleanly.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the SK Contribution Guidelines
  • All unit tests pass locally (26/26 tests passing)
  • Ruff check and format pass cleanly

…ializing (microsoft#14755)

Dict and dataclass records reach the Chroma serializer keyed by storage name and pydantic models keyed by field name. The serializer read the key by declared name and the vector by storage name, so a dict or dataclass record with a storage_name on the key field failed to upsert and a pydantic model with a storage_name on the vector field failed too. The deserializer returned the key and the vector under the declared names, which the data model step does not read for dict and dataclass records, so a vector with a storage_name came back as None. Pydantic metadata was stored under the declared names, so filters on storage names did not match it.

Closes microsoft#14755

Co-authored-by: VANDRANKI <[email protected]>
Copilot AI balanced review requested due to automatic review settings November 9, 2026 16:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks correct. Here's what I checked.

  • Which keys reach the serializer. _serialize_data_model_to_dict (data/vector.py) returns record.model_dump() for pydantic models, which is keyed by declared name. For dicts and dataclasses it builds store_model[field.storage_name or field.name]. So the description is right that the two arrive keyed differently, and _storage_keyed (chroma.py:212) moves the pydantic case onto storage names without touching the other.
  • Which keys the deserializer must produce. _deserialize_dict_to_data_model pops storage_name to name for pydantic records and reads record.get(field.storage_name or field.name) for the others. Returning the key and vector under their storage names (chroma.py:249-250) is what both paths expect. On main, the vector came back under vector_field.name and was read as None for dict records with a vector storage_name.
  • Collisions. _storage_keyed only renames when the storage name isn't already a key, so a field whose storage name equals another field's declared name won't be overwritten.
  • git merge-tree against main is clean.

I didn't run the tests.

One thing worth a line in the release notes: for pydantic models with a storage_name on a data field, metadata used to be written under the declared name and is now written under the storage name. A collection with older records will then have both spellings, and a filter on the storage name won't match the older ones. Reads still work for both, because the pydantic path accepts either key.

Reviewed with help from Claude Code.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants