Skip to content

[Bug]: active-memory timeout closes shared QMD memory_search manager #96455

Description

@ShibukiZero

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

After an active-memory embedded recall run times out, chat-session memory_search can return "memory search manager is closed" even though openclaw memory search --agent main succeeds against the same QMD backend.

Steps to reproduce

  1. Run OpenClaw with memory-core using the QMD backend for agent main.
  2. Enable the active-memory plugin for main with a short enough timeout to reproduce timeout behavior, for example timeoutMs: 5000 and queryMode: "message".
  3. Use an active-memory model/path that times out during the embedded recall run.
  4. Send a normal user message that triggers active-memory before prompt build.
  5. Observe active-memory timeout logs similar to active-memory: agent=main ... done status=timeout elapsedMs=10007 summaryChars=0.
  6. Immediately call the chat-session memory_search tool in the same gateway/session.
  7. Observe memory_search returning unavailable with error: "memory search manager is closed".
  8. In parallel, run openclaw memory search "<same topic>" --agent main from CLI and observe that CLI search succeeds.

Expected behavior

An active-memory timeout should cancel or skip only that active-memory recall attempt. It should not close the long-lived/shared QMD manager used by normal chat-session memory_search calls.

Chat memory_search should remain available when the QMD backend is healthy and CLI search for the same agent works.

Actual behavior

After active-memory times out, chat-session memory_search returns a disabled/unavailable result like:

{
  "results": [],
  "disabled": true,
  "unavailable": true,
  "error": "memory search manager is closed",
  "action": "Check embedding provider configuration and retry memory_search."
}

The first closed-manager result can also put the memory tool into its 60s cooldown, so subsequent chat memory_search calls keep returning unavailable without immediately recreating a fresh manager.

OpenClaw version

Observed on 2026.6.9 (c645ec4). Current main source inspected at 1069c60e1e still contains the same active-memory timeout cleanup shape.

Operating system

macOS 26.5.1 (25F80)

Install method

NOT_ENOUGH_INFO

Model

active-memory model observed: openrouter/openai/gpt-oss-20b

Provider / routing chain

OpenClaw gateway -> active-memory embedded agent -> memory_search / memory_get; memory backend is QMD via /opt/homebrew/bin/qmd.

Additional provider/model setup details

Relevant observed setup:

  • Node: v26.3.0
  • qmd: 2.5.3 (686144996e)
  • Memory backend: QMD
  • QMD search mode: lexical searchMode: "search"
  • active-memory agents: ["main"]
  • active-memory timeoutMs: 5000
  • active-memory default tools: memory_search, memory_get

Logs, screenshots, and evidence

Observed gateway timeline, local time UTC+8:

19:31:24  active-memory: agent=main start timeoutMs=5000
19:31:34  qmd watcher starting for agent "main" paths=2
19:31:34  qmd manager initialized for agent "main" mode=full collections=2
19:31:34  qmd watcher ready for agent "main"
19:31:34  qmd sync completed for agent "main" reason=boot
19:31:35  active-memory: agent=main done status=timeout elapsedMs=10007
19:31:37  embedded abort settle timed out: runId=active-memory-...
19:31:37  embedded run failover decision: aborted=true decision=surface_error

After this, three chat memory_search tool calls returned "memory search manager is closed". The pattern repeated after later active-memory timeouts. CLI search continued to succeed for the same agent/backend.

Source evidence from current main (1069c60e1e):

extensions/active-memory/index.ts
- DEFAULT_ACTIVE_MEMORY_TOOLS_ALLOW is ["memory_search", "memory_get"].
- runRecallSubagent calls api.runtime.agent.runEmbeddedAgent(... toolsAllow: [...params.config.toolsAllow], abortSignal: params.abortSignal ...).
- maybeResolveActiveRecall schedules timeout cleanup on active-memory timeout/parent abort.
- scheduleMemorySearchCleanupAfterTimeout calls closeActiveMemorySearchManager({ cfg, agentId }).

extensions/memory-core/src/memory/search-manager.ts
- QMD full managers are cached by buildQmdManagerScopeKey(agentId), currently just the agent id.
- Non-status, non-cli callers receive the cached full manager.
- closeMemorySearchManager deletes QMD_MANAGER_CACHE[agentId] and calls cached.manager.close().
- FallbackMemoryManager.close() sets closed=true.
- FallbackMemoryManager.ensureOpen() throws "memory search manager is closed".

extensions/memory-core/src/tools.ts
- memory_search only tracks/closes managers for oneShotCliRun / purpose="cli".
- normal chat memory_search does not close the shared manager itself.
- memory_search treats "memory search manager is closed" as a closed-store error and may retry once, but the first unavailable result can still enter the tool cooldown path.

src/gateway/server-startup-memory.ts
- startup uses purpose="default" when a long-lived QMD manager is needed for timers/intervals, and purpose="cli" only for one-shot boot sync.

This points to active-memory timeout cleanup closing an agent-scoped shared QMD manager, rather than only aborting the request-scoped embedded recall.

Impact and severity

Affected: users with active-memory enabled and QMD-backed memory_search in chat sessions.

Severity: High for memory-dependent workflows. When it triggers, chat memory recall becomes unavailable even though QMD and CLI search are healthy.

Frequency: Reproduces after active-memory timeout in the observed setup; repeated timeouts can repeatedly re-close the manager.

Consequence: the agent appears to have broken or disabled memory, and the 60s memory_search cooldown can make recovery look sticky until cooldown expires or the gateway is restarted.

Additional information

Related but not duplicate issues found before filing:

This issue is narrower: active-memory timeout cleanup closes the shared QMD full manager used by chat memory_search, causing the specific "memory search manager is closed" failure.

Possible fix directions:

  1. Remove or narrow active-memory's timeout cleanup so it does not call closeActiveMemorySearchManager for the agent-scoped shared full manager.
  2. Treat active-memory timeout as request-scoped cancellation only; rely on the embedded run abort signal and the memory_search tool's own abort signal to cancel in-flight QMD subprocess work.
  3. If active-memory needs disposable memory-search resources, run its internal recall against an isolated one-shot/CLI-style manager that is not stored in the shared full-manager cache.
  4. Add a regression test where an active-memory timeout overlaps with a normal chat memory_search; the normal tool call should not surface "memory search manager is closed" and should either complete or recreate a fresh manager without entering cooldown.
  5. Consider not recording closed-manager errors into the 60s memory_search cooldown, because this is usually a lifecycle/race recovery case rather than an embedding-provider outage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:linked-pr-openClawSweeper found an open linked pull request for this issue.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions