You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Async extract/addMessage/commit endpoints return 200 OK even when the work fails — silent data loss for the Python integration #56
OpenMemoryController.extract, addMessage, and commit are fire-and-forget. They return 200 OK immediately and dispatch the real work onto a separate scheduler. Any failure in the dispatched work is logged on the server and lost everywhere else. The Python ingest.py retry spool only triggers on transport-level failures, so a server-side exception here results in silent, unrecoverable data loss from the client's perspective.
Details
This is a common pattern that can lead to subtle data loss when async endpoints are placed in front of a retry-aware client. Looking at the controller:
extractAsync schedules onto Schedulers.boundedElastic (see OpenMemoryApplicationService.dispatchAsync, ~line 222) and any error is handled with a log.error(...) only. The HTTP response has already been sent before the scheduled task runs.
Now the client side, memind-integrations/claude-code/scripts/lib/client.py:
A 200 OK with a successful envelope is the success criterion. Combined with ingest.py (lines 82–95), where the retry spool only enqueues on requests-level exceptions or non-success envelopes, this means:
DB unavailable mid-extract → server logs it → client thinks it succeeded → message is marked submitted in state.json → never retried.
Vector store down → same outcome.
Any extraction-pipeline bug that throws after the HTTP boundary → same outcome.
Synchronous endpoint variants for clients that need durability — /extract/sync returns the actual outcome. The async variant remains for callers who explicitly want fire-and-forget.
Server-side durable queue: persist the request before returning 200, and have the async worker drain from that queue. Then 200 truly means "we have it." This is heavier but matches the user's intuition.
Either is fine; the status quo just shouldn't be the only option.
This is a real Open API reliability gap: these endpoints currently acknowledge dispatch, not completion or durable enqueue, so we’ll add a synchronous/durable path for retry-safe clients before the 0.2.0 release while keeping the async path for fire-and-forget use cases.
Activity
starboyate commentedon May 10, 2026
This is a real Open API reliability gap: these endpoints currently acknowledge dispatch, not completion or durable enqueue, so we’ll add a synchronous/durable path for retry-safe clients before the 0.2.0 release while keeping the async path for fire-and-forget use cases.