From 32a4882a1018e7e1542324557cb104ad24340c80 Mon Sep 17 00:00:00 2001 From: And#ocean Date: Tue, 10 Mar 2026 18:44:04 +0300 Subject: [PATCH] fix: resolve remaining webhook schema issues in multi-tenant retain (#533) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #499 which fixed the worker path and http.py but missed two code paths in memory_engine.py: 1. `_retain_batch_async_internal` (line ~2185) still passed `request_context.tenant_id` which is always None for HTTP requests (tenant_id is never populated by the HTTP layer — the schema is stored in the _current_schema contextvar by _authenticate_tenant). 2. `_build_retain_outbox_callback._callback` captured the `schema` parameter at closure creation time. In the HTTP path, http.py builds the callback *before* calling retain_batch_async, but _current_schema is only set inside retain_batch_async by _authenticate_tenant — so the captured schema is always None. Fixed by resolving schema at callback invocation time via `schema or _current_schema.get()`. Both issues cause `relation "webhooks" does not exist` errors that abort the entire retain transaction in multi-tenant deployments, silently rolling back all inserted memory data. --- hindsight-api/hindsight_api/engine/memory_engine.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hindsight-api/hindsight_api/engine/memory_engine.py b/hindsight-api/hindsight_api/engine/memory_engine.py index ad0de183..4bbec15b 100644 --- a/hindsight-api/hindsight_api/engine/memory_engine.py +++ b/hindsight-api/hindsight_api/engine/memory_engine.py @@ -1139,8 +1139,13 @@ class MemoryEngine(MemoryEngineInterface): ) async def _callback(conn: asyncpg.Connection) -> None: + # Resolve schema at call time (not at callback creation time) because + # _current_schema contextvar may not yet be set when the callback is built + # from the HTTP path (http.py calls _build_retain_outbox_callback before + # retain_batch_async which is where _authenticate_tenant sets the schema). + resolved_schema = schema or _current_schema.get() for event in events: - await webhook_manager.fire_event_with_conn(event, conn, schema=schema) + await webhook_manager.fire_event_with_conn(event, conn, schema=resolved_schema) return _callback @@ -2182,7 +2187,7 @@ class MemoryEngine(MemoryEngineInterface): document_tags=document_tags, config=resolved_config, operation_id=operation_id, - schema=request_context.tenant_id if request_context else None, + schema=_current_schema.get(), outbox_callback=outbox_callback, )