openclaw - ✅(Solved) Fix memory-core: dreaming subagent lacks operator.admin to delete its own session [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#70353Fetched 2026-04-23 07:25:48
View on GitHub
Comments
0
Participants
1
Timeline
1
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1

The dreaming cron in memory-core runs subagent.deleteSession() after generating a narrative entry, but the embedded subagent runner is invoked without operator.admin scope. Result: every dream cycle (light, REM, deep × number of agents) emits narrative session cleanup failed: missing scope: operator.admin.

The narrative itself is generated and written successfully — only the post-generation session cleanup fails, leaving stale session entries that have to be cleaned externally.

Error Message

params.logger.warn(memory-core: narrative session cleanup failed for ${params.data.phase} phase: ${formatErrorMessage(cleanupErr)});

  • Repeated WARN log noise (multiple lines per dream cycle × multiple agents)

Root Cause

The dreaming cron in memory-core runs subagent.deleteSession() after generating a narrative entry, but the embedded subagent runner is invoked without operator.admin scope. Result: every dream cycle (light, REM, deep × number of agents) emits narrative session cleanup failed: missing scope: operator.admin.

The narrative itself is generated and written successfully — only the post-generation session cleanup fails, leaving stale session entries that have to be cleaned externally.

Fix Action

Fix / Workaround

  • LXC container, Debian 12, Node 22.22.2
  • 14 agents, dreaming enabled per agent
  • Cron is running and working (systemctl status cron shows active)
  • Workaround: external prune-dream-sessions.sh at 03:30 UTC catches what the failed cleanup leaves behind

PR fix notes

PR #69890: fix(plugins): grant admin scope to synthetic subagent deleteSession

Description (problem / solution / changelog)

Summary

Fixes #69886. memory-core's Memory Dreaming Promotion cron invokes narrative cleanup in a `finally` block after the narrative run settles. By that point the cron's original request scope has unwound, so `createGatewaySubagentRuntime().deleteSession` falls through to `createSyntheticOperatorClient`, which defaults to `["operator.write"]`.

`sessions.delete` is gated under `ADMIN_SCOPE` in `method-scopes.ts` (line 165), so the synthetic fallback fails nightly with:

``` [plugins] memory-core: narrative session cleanup failed for light phase: missing scope: operator.admin [plugins] memory-core: narrative session cleanup failed for rem phase: missing scope: operator.admin [plugins] memory-core: narrative session cleanup failed for deep phase: missing scope: operator.admin ```

Dream diary entries are written fine — only the spawned narrative sessions end up orphaned.

Fix

Pass `{ syntheticScopes: [ADMIN_SCOPE] }` to the `dispatchGatewayMethod` call for `sessions.delete` — the surgical patch from the issue report's option 1. Other methods on the subagent runtime (`run`, `getSession`, etc.) still use their default write scope; only the admin-gated one asks for admin.

Test

The existing test `rejects fallback session deletion without minting admin scope` asserted the buggy behavior (it locked in the regression). Updated it to the regression test for #69886: asserts `resolves.toBeUndefined()` and that `getLastDispatchedClientScopes()` returns exactly `["operator.admin"]` — admin-only, not a broader bundle, so plugins cannot escalate beyond the specific method requirement.

oxlint passes on both changed files.

Closes #69886.

Changed files

  • src/gateway/server-plugins.test.ts (modified, +11/-6)
  • src/gateway/server-plugins.ts (modified, +16/-4)

Code Example

"memory-core": {
     "enabled": true,
     "config": { "dreaming": { "enabled": true, "frequency": "0 3 * * *" } }
   }

---

memory-core: dreaming cleanup scrubbed 0 stale session entries and archived 42 orphan transcripts.
   memory-core: narrative session cleanup failed for light phase: missing scope: operator.admin
   memory-core: narrative session cleanup failed for rem phase: missing scope: operator.admin
   memory-core: narrative session cleanup failed for deep phase: missing scope: operator.admin

---

if (params.subagent) try {
  await params.subagent.deleteSession({ sessionKey });
} catch (cleanupErr) {
  params.logger.warn(`memory-core: narrative session cleanup failed for ${params.data.phase} phase: ${formatErrorMessage(cleanupErr)}`);
}
RAW_BUFFERClick to expand / collapse

memory-core: dreaming subagent lacks operator.admin to delete its own session

openclaw version: 2026.4.20 (commit 115f05d) Pre-existing in: at least 2026.4.15

Summary

The dreaming cron in memory-core runs subagent.deleteSession() after generating a narrative entry, but the embedded subagent runner is invoked without operator.admin scope. Result: every dream cycle (light, REM, deep × number of agents) emits narrative session cleanup failed: missing scope: operator.admin.

The narrative itself is generated and written successfully — only the post-generation session cleanup fails, leaving stale session entries that have to be cleaned externally.

Reproduction

  1. Configure dreaming:

    "memory-core": {
      "enabled": true,
      "config": { "dreaming": { "enabled": true, "frequency": "0 3 * * *" } }
    }
  2. Wait for cron to fire (or trigger manually)

  3. Observe in /tmp/openclaw/openclaw-YYYY-MM-DD.log:

    memory-core: dreaming cleanup scrubbed 0 stale session entries and archived 42 orphan transcripts.
    memory-core: narrative session cleanup failed for light phase: missing scope: operator.admin
    memory-core: narrative session cleanup failed for rem phase: missing scope: operator.admin
    memory-core: narrative session cleanup failed for deep phase: missing scope: operator.admin

Source location

dist/dreaming-narrative-D2j0t41s.js:597 (in 2026.4.20):

if (params.subagent) try {
  await params.subagent.deleteSession({ sessionKey });
} catch (cleanupErr) {
  params.logger.warn(`memory-core: narrative session cleanup failed for ${params.data.phase} phase: ${formatErrorMessage(cleanupErr)}`);
}

The subagent context is created by manager-runtime.js for the dreaming sweep without admin scope. The deleteSession API path requires operator.admin per server.impl-DYBxSjUs.js:10196 (ADMIN_SCOPE = "operator.admin").

Suggested fix

Either:

  1. Auto-grant operator.admin to the subagent runner spawned by the dreaming cron (it's the same trust boundary as the parent gateway, owns its own session).
  2. Provide a subagent.deleteOwnSession() API that doesn't require admin scope when called by the session's own creator.
  3. Use a separate cleanup path that doesn't go through the scope-gated HTTP delete.

Impact

  • Repeated WARN log noise (multiple lines per dream cycle × multiple agents)
  • Stale session entries accumulate; require external cleanup script (prune-dream-sessions.sh cron at 03:30 UTC handles this for us)
  • managed dreaming cron could not be reconciled (cron service unavailable) — related warning suggesting the dreaming control plane is partially broken too

Environment

  • LXC container, Debian 12, Node 22.22.2
  • 14 agents, dreaming enabled per agent
  • Cron is running and working (systemctl status cron shows active)
  • Workaround: external prune-dream-sessions.sh at 03:30 UTC catches what the failed cleanup leaves behind

extent analysis

TL;DR

Grant the operator.admin scope to the subagent runner or implement an alternative cleanup method that doesn't require admin scope.

Guidance

  • Verify the subagent runner's scope configuration to confirm it lacks operator.admin permissions.
  • Consider implementing a subagent.deleteOwnSession() API that allows a subagent to delete its own session without requiring operator.admin scope.
  • Evaluate using a separate cleanup path that bypasses the scope-gated HTTP delete, as an alternative to granting admin scope to the subagent runner.
  • Review the prune-dream-sessions.sh script to ensure it effectively handles stale session cleanup and consider integrating its functionality into the dreaming cron.

Example

No explicit code example is provided, but the suggested fix implies modifying the dist/dreaming-narrative-D2j0t41s.js file to either grant operator.admin scope or implement an alternative cleanup method.

Notes

The issue is specific to the memory-core dreaming functionality and the operator.admin scope requirement for the deleteSession API. The suggested fixes aim to address the root cause of the problem, but the best approach may depend on the specific requirements and constraints of the system.

Recommendation

Apply a workaround by implementing a subagent.deleteOwnSession() API that doesn't require operator.admin scope, as this approach avoids granting elevated permissions to the subagent runner and maintains a clear separation of concerns.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix memory-core: dreaming subagent lacks operator.admin to delete its own session [1 pull requests, 1 participants]