fix(vectordb): truncate oversized fields JSON blob before bytes_row write - #3593
fix(vectordb): truncate oversized fields JSON blob before bytes_row write#3593TurgutKural wants to merge 1 commit into
Conversation
…rite The local vectordb bytes_row format length-prefixes every string field with a uint16, capping each at 65535 bytes. The fields column stores all scalar metadata (abstract, description, name, tags, uri, ...) as a single JSON blob. When a large abstract (~50KB after the #2774 cap) is combined with other scalar fields, the total serialized blob can exceed 65535 bytes, causing: RuntimeError: string field 'fields' exceeds 65535 bytes This was partially addressed by #3114 (drop content field for non- VikingDB backends) and #2774 (cap abstract at 50KB), but the combined JSON blob of all remaining scalars can still overflow. Fix: add LocalCollection._truncate_fields_json() which serializes the payload once, and if it exceeds the limit, iteratively halves the longest string value until the blob fits. Non-string fields (level, active_count, timestamps) are never modified. The URI field survives truncation as long as possible since it is the primary lookup key. Includes 7 unit tests covering: small passthrough, single large field, multiple large fields, non-string preservation, empty dict, boundary exact fit, and multi-byte UTF-8 truncation. Fixes the remaining gap after #2967 / #3114. Related: #2117, #2774, #2966
|
Adding a production data point in support of this fix: we hit the exact Two takeaways from that incident that this PR's approach addresses:
I've opened #4135 as a complementary client-side cap for the claude-code plugin's capture paths so oversized (or surrogate-broken) text parts never leave the client, which protects servers on already-released versions -- but the server-side truncation here is the fix that covers every producer. |
Description
The local vectordb
bytes_rowformat length-prefixes every string field with auint16, capping each at 65 535 bytes. Thefieldscolumn stores all scalar metadata (abstract, description, name, tags, uri, …) as a single JSON blob. When a large abstract (~50 KB after the #2774 cap) is combined with other scalar fields, the total serialized blob can exceed 65 535 bytes, causing:This was partially addressed by #3114 (drop
contentfield for non-VikingDB backends) and #2774 (cap abstract at 50 KB), but the combined JSON blob of all remaining scalars can still overflow.Root cause
local_collection.py:844:datacontains every scalar field from the collection schema (uri, context_type, abstract, description, name, tags, account_id, owner_user_id, created_at, updated_at, level, active_count). Theabstractalone can be up to 50 000 bytes after the #2774 truncation. Adding the remaining fields pushes the JSON blob past 65 535 bytes.Fix
Add
LocalCollection._truncate_fields_json()which:level,active_count, timestamps) are never modified.The write path now calls
self._truncate_fields_json(data)instead ofsafe_json_dumps(data).Related
Type of Change
Changes Made
openviking/storage/vectordb/collection/local_collection.py: add_truncate_fields_json()static method + importSTRING_MAX_UINT16_LENGTH; replacesafe_json_dumpscall in_write_data_listtests/storage/test_fields_json_truncation.py: 7 unit tests (small passthrough, single large field, multiple large fields, non-string preservation, empty dict, boundary exact fit, multi-byte UTF-8)Testing
Verified against a live deployment with 5 memory files (82–131 KB) that previously failed with
string field 'fields' exceeds 65535 bytes. After the fix, all 5 records are written successfully.