openclaw - 💡(How to fix) Fix session file changed while embedded prompt lock was released

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…

Reproduction:

  1. User requests image generation in a session
  2. onYield sets yieldDetected=true and calls runAbortController.abort("sessions_yield")
  3. Yield handler calls releaseHeldLockForAbort() — releases the session file write lock and records a fence fingerprint
  4. Image generation completes in background → wakeMediaGenerationTaskCompletion → deliverSubagentAnnouncement with expectsCompletionMessage: true
  5. Dispatch goes direct-first → sendSubagentAnnounceDirectly attempts active wake on the yielded run
  6. prepareEmbeddedPiQueueMessage checks isStreaming() → returns "not_streaming" (yielded run is not streaming) → wake fails, activeRequesterWakeFailed=true
  7. Falls through to runAnnounceAgentCall which launches a new embedded run on the same session
  8. New run acquires its own write lock → writes completion message to session file → releases lock
  9. New run's writes are not tracked in the original run's ownedSessionFileWrites (separate lock controller instances)
  10. Original run reacquires lock → assertSessionFileFence detects fingerprint mismatch
  11. ownedSessionFileWrites is null for this session → owned-write check fails
  12. trustedSessionFileStates is stale (fingerprint.exists: false) → trusted-state check fails
  13. Benign checks fail (appended content includes non-transcript-only entries from the announce run)
  14. EmbeddedAttemptSessionTakeoverError is thrown

Root cause: After sessions_yield, the original run cannot be woken (no resume mechanism), forcing sendSubagentAnnounceDirectly to launch a new agent run. The new run writes to the session file, but its writes are invisible to the original run's lock controller. When the original run reacquires the lock, the fence check has no way to distinguish these legitimate announce-run writes from external tampering.

Two underlying issues:

  • Yield has no resume/wake mechanism — a yielded run stays in ACTIVE_EMBEDDED_RUNS but isStreaming=false, making it unwakeable for steer or active-wake delivery
  • Two concurrent embedded attempts on the same session file don't share owned-write tracking across lock controller instances

Error Message

00:13:09 [agent/embedded] embedded attempt cleanup detected session takeover after prompt failure; preserving prompt error: runId=image_generate:cafe4a33-2d5c-4032-88b1-438a60a71f8e:ok sessionId=dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc promptError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl cleanupError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl 00:13:09 [diagnostic] lane task error: lane=main durationMs=203828 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl" 00:13:09 [diagnostic] lane task error: lane=session:agent:user:a:direct:xdurationMs=203836 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl" 00:13:09 [diagnostic] lane wait exceeded: lane=session:agent:user:a:direct:x waitedMs=46116 queueAhead=0 activeAhead=1 activeNow=0 queueBehind=0

Root Cause

Root cause: After sessions_yield, the original run cannot be woken (no resume mechanism), forcing sendSubagentAnnounceDirectly to launch a new agent run. The new run writes to the session file, but its writes are invisible to the original run's lock controller. When the original run reacquires the lock, the fence check has no way to distinguish these legitimate announce-run writes from external tampering.

Fix Action

Fix / Workaround

  1. User requests image generation in a session
  2. onYield sets yieldDetected=true and calls runAbortController.abort("sessions_yield")
  3. Yield handler calls releaseHeldLockForAbort() — releases the session file write lock and records a fence fingerprint
  4. Image generation completes in background → wakeMediaGenerationTaskCompletion → deliverSubagentAnnouncement with expectsCompletionMessage: true
  5. Dispatch goes direct-first → sendSubagentAnnounceDirectly attempts active wake on the yielded run
  6. prepareEmbeddedPiQueueMessage checks isStreaming() → returns "not_streaming" (yielded run is not streaming) → wake fails, activeRequesterWakeFailed=true
  7. Falls through to runAnnounceAgentCall which launches a new embedded run on the same session
  8. New run acquires its own write lock → writes completion message to session file → releases lock
  9. New run's writes are not tracked in the original run's ownedSessionFileWrites (separate lock controller instances)
  10. Original run reacquires lock → assertSessionFileFence detects fingerprint mismatch
  11. ownedSessionFileWrites is null for this session → owned-write check fails
  12. trustedSessionFileStates is stale (fingerprint.exists: false) → trusted-state check fails
  13. Benign checks fail (appended content includes non-transcript-only entries from the announce run)
  14. EmbeddedAttemptSessionTakeoverError is thrown

Code Example

00:13:09 [agent/embedded] embedded attempt cleanup detected session takeover after prompt failure; preserving prompt error: runId=image_generate:cafe4a33-2d5c-4032-88b1-438a60a71f8e:ok sessionId=dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc promptError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl cleanupError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl
00:13:09 [diagnostic] lane task error: lane=main durationMs=203828 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl"
00:13:09 [diagnostic] lane task error: lane=session:agent:user:a:direct:xdurationMs=203836 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl"
00:13:09 [diagnostic] lane wait exceeded: lane=session:agent:user:a:direct:x waitedMs=46116 queueAhead=0 activeAhead=1 activeNow=0 queueBehind=0
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Beta release blocker

No

Summary

Reproduction:

  1. User requests image generation in a session
  2. onYield sets yieldDetected=true and calls runAbortController.abort("sessions_yield")
  3. Yield handler calls releaseHeldLockForAbort() — releases the session file write lock and records a fence fingerprint
  4. Image generation completes in background → wakeMediaGenerationTaskCompletion → deliverSubagentAnnouncement with expectsCompletionMessage: true
  5. Dispatch goes direct-first → sendSubagentAnnounceDirectly attempts active wake on the yielded run
  6. prepareEmbeddedPiQueueMessage checks isStreaming() → returns "not_streaming" (yielded run is not streaming) → wake fails, activeRequesterWakeFailed=true
  7. Falls through to runAnnounceAgentCall which launches a new embedded run on the same session
  8. New run acquires its own write lock → writes completion message to session file → releases lock
  9. New run's writes are not tracked in the original run's ownedSessionFileWrites (separate lock controller instances)
  10. Original run reacquires lock → assertSessionFileFence detects fingerprint mismatch
  11. ownedSessionFileWrites is null for this session → owned-write check fails
  12. trustedSessionFileStates is stale (fingerprint.exists: false) → trusted-state check fails
  13. Benign checks fail (appended content includes non-transcript-only entries from the announce run)
  14. EmbeddedAttemptSessionTakeoverError is thrown

Root cause: After sessions_yield, the original run cannot be woken (no resume mechanism), forcing sendSubagentAnnounceDirectly to launch a new agent run. The new run writes to the session file, but its writes are invisible to the original run's lock controller. When the original run reacquires the lock, the fence check has no way to distinguish these legitimate announce-run writes from external tampering.

Two underlying issues:

  • Yield has no resume/wake mechanism — a yielded run stays in ACTIVE_EMBEDDED_RUNS but isStreaming=false, making it unwakeable for steer or active-wake delivery
  • Two concurrent embedded attempts on the same session file don't share owned-write tracking across lock controller instances

Steps to reproduce

  1. Start a conversation with an agent that has image generation enabled
  2. Request the agent to generate an image (e.g., "generate an image of a cat")
  3. The agent invokes image_generate tool → notifyMediaGenerationAsyncTaskStarted triggers sessions_yield
  4. The main run yields, releasing the session file write lock
  5. Wait for image generation to complete in the background
  6. wakeMediaGenerationTaskCompletion fires → deliverSubagentAnnouncement → sendSubagentAnnounceDirectly
  7. Active wake fails (yielded run isStreaming() === false)
  8. runAnnounceAgentCall launches a new embedded run that writes to the session file
  9. Original run reacquires the write lock → assertSessionFileFence throws EmbeddedAttemptSessionTakeoverError

Expected behavior

Image generation completion should be delivered to the requesting session without triggering a takeover error. The fence check should recognize that announce-run writes on behalf of a yielded session are legitimate.

Actual behavior

EmbeddedAttemptSessionTakeoverError is thrown because the new announce run's writes are not tracked in the original run's ownedSessionFileWrites, and benign checks fail for non-transcript-only appended content.

OpenClaw version

2026.5.27

Operating system

mac0s

Install method

pnpm dev

Model

gpt-5.5

Provider / routing chain

gpt-5.5

Additional provider/model setup details

No response

Logs, screenshots, and evidence

00:13:09 [agent/embedded] embedded attempt cleanup detected session takeover after prompt failure; preserving prompt error: runId=image_generate:cafe4a33-2d5c-4032-88b1-438a60a71f8e:ok sessionId=dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc promptError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl cleanupError=session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl
00:13:09 [diagnostic] lane task error: lane=main durationMs=203828 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl"
00:13:09 [diagnostic] lane task error: lane=session:agent:user:a:direct:xdurationMs=203836 error="EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released: /.openclaw/agents/user/sessions/dc4e36a6-8a19-4a52-9d0c-cc4d65bbd9dc.jsonl"
00:13:09 [diagnostic] lane wait exceeded: lane=session:agent:user:a:direct:x waitedMs=46116 queueAhead=0 activeAhead=1 activeNow=0 queueBehind=0

Impact and severity

No response

Additional information

No response

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…

FAQ

Expected behavior

Image generation completion should be delivered to the requesting session without triggering a takeover error. The fence check should recognize that announce-run writes on behalf of a yielded session are legitimate.

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 - 💡(How to fix) Fix session file changed while embedded prompt lock was released