fix: vector count returns 0 due to account_id mismatch in observer#802
fix: vector count returns 0 due to account_id mismatch in observer#802jackjin1997 wants to merge 1 commit intovolcengine:mainfrom
Conversation
Fixes volcengine#786 Root cause: VikingDBObserver.count() calls the backend without a RequestContext, which defaults to filtering by account_id='default'. When vectors are written with a different account_id (from the user's actual context), the count query misses them entirely. Fix: Add include_all_accounts parameter to count(). When True, uses the root backend (no account_id filter) to count all vectors across all tenants. The observer and get_collection_info now use this to report accurate totals.
|
|
qin-ctx
left a comment
There was a problem hiding this comment.
Thanks for the investigation — the root cause analysis of the account_id mismatch is correct. However, the fix direction needs reconsideration.
Multi-tenant isolation concern
Using include_all_accounts=True bypasses tenant isolation, which breaks the multi-tenant contract. The observer API is called with a user's API key (each tenant has their own), so it should only return that tenant's vector count — not a global total across all accounts.
The real issue is that RequestContext is available at the router level (observer.py:57, the _ctx parameter) but is never passed down the chain:
router (has _ctx but ignores it)
→ ObserverService.vikingdb (property, no params)
→ VikingDBObserver (no ctx)
→ vikingdb_manager.count() (no ctx → defaults to account_id="default")
The proper fix would be to propagate ctx through the observer chain so count(ctx=ctx) queries the correct tenant's data.
Runtime bug in _SingleAccountBackend.get_collection_info()
The diff modifies get_collection_info() at line 133, which belongs to the inner class _SingleAccountBackend. It changes self.count() to self.count(include_all_accounts=True), but _SingleAccountBackend.count() (line 352) has this signature:
async def count(self, filter: Optional[Dict[str, Any] | FilterExpr] = None) -> int:It does not accept include_all_accounts. This will raise TypeError: count() got an unexpected keyword argument 'include_all_accounts' at runtime.
Suggested approach
- Pass
ctxfrom the router →ObserverService→VikingDBObserver→vikingdb_manager.count(ctx=ctx) - Each tenant sees only their own vector count
- No need for the
include_all_accountsparameter
|
Hi @jackjin1997, thanks for digging into this — your root cause analysis of the We've opened an alternative fix in #807 that takes a different approach: instead of Also heads-up on a runtime issue in this PR: the diff modifies Feel free to take a look at #807 and let us know if you have any thoughts! |
Summary
Fixes #786
Root Cause
VikingDBObserver.count()callsVikingVectorIndexBackend.count(ctx=None), which defaults to_get_default_backend()— a backend bound toaccount_id="default".When vectors are written with a different
account_id(derived from the user'sRequestContextinTextEmbeddingHandler), the count query filters them out, returning 0 even though vectors are properly persisted in LevelDB.Code path:
Fix
include_all_accounts: boolparameter toVikingVectorIndexBackend.count()True, uses_get_root_backend()(noaccount_idfilter) to count all vectorsVikingDBObserverandget_collection_info()to useinclude_all_accounts=Truectxor default behavior unchangedChanges
openviking/storage/viking_vector_index_backend.py— addinclude_all_accountsparam tocount(), fixget_collection_infoopenviking/storage/observers/vikingdb_observer.py— useinclude_all_accounts=True