Skip to content

fix(embedded-agent-runner): false positive EmbeddedAttemptSessionTakeoverError during session compaction#88348

Closed
raymondjxj wants to merge 1 commit into
openclaw:mainfrom
raymondjxj:fix/session-fence-compaction-false-positive
Closed

fix(embedded-agent-runner): false positive EmbeddedAttemptSessionTakeoverError during session compaction#88348
raymondjxj wants to merge 1 commit into
openclaw:mainfrom
raymondjxj:fix/session-fence-compaction-false-positive

Conversation

@raymondjxj

Copy link
Copy Markdown

Bug Summary

Error: EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was released
Symptom: OpenClaw bot stops processing messages, repeating lane task error + Embedded agent failed before reply
Root cause location: src/agents/embedded-agent-runner/run/attempt.session-lock.ts, sessionFenceRewriteIsBenign()

Root Cause

When a prompt is being streamed, releaseForPrompt() releases the write lock on the session file and sets fenceActive = true. While the lock is released (during LLM streaming), OpenClaw's compaction process may rewrite the session file to compact old messages.

When reacquireAfterPrompt() re-acquires the lock and calls assertSessionFileFence(), the fence check fails because:

  1. sessionFenceRewriteIsBenign has sameSessionFileIdentity() (inode comparison) as its first guard condition (line 266)
  2. Compaction creates a new file with a new inode even though the content is valid
  3. sameSessionFileIdentity returns false → function returns false immediately without reaching content validation
  4. Both sessionFenceAdvanceIsBenign and sessionFenceRewriteIsBenign return false
  5. EmbeddedAttemptSessionTakeoverError is thrown (false positive)

The Fix

Remove sameSessionFileIdentity() from the early-return guard in sessionFenceRewriteIsBenign. The function already rigorously validates content via lineMatchesLinearTranscriptMigration + isTranscriptOnlyOpenClawAssistantLine. When content validation passes, the rewrite is safe regardless of whether the inode changed — a compaction rewrite with new inode is benign.

- !sameSessionFileIdentity(params.previous.fingerprint, params.current) ||
  params.current.size > BigInt(MAX_BENIGN_SESSION_FENCE_REWRITE_RESULT_BYTES) ||

And the terminal return statement becomes a content-check + true:

- return appendedLines.every(isTranscriptOnlyOpenClawAssistantLine);
+ if (!appendedLines.every(isTranscriptOnlyOpenClawAssistantLine)) {
+   return false;
+ }
+ // Content validation passed — benign rewrite regardless of inode.
+ return true;

Why This Is Safe

The lineMatchesLinearTranscriptMigration + isTranscriptOnlyOpenClawAssistantLine content validation rigorously confirms:

  • All previous transcript lines are preserved unchanged
  • Only legitimate OpenClaw assistant lines were appended

If a malicious process tried to fake a "compaction", it would need to produce content that passes this validation AND still trigger the takeover — which is impossible by design.

Reproduction Scenario

  1. User sends message to Telegram bot (ling agent)
  2. DeepSeek starts streaming response
  3. releaseForPrompt() releases write lock (to allow streaming)
  4. Compaction triggers and rewrites ~/.openclaw/agents/ling/sessions/{session-id}.jsonl
  5. reacquireAfterPrompt() detects file changed → throws EmbeddedAttemptSessionTakeoverError
  6. Bot enters error loop: lane task error + Embedded agent failed before reply

Testing

  • No existing unit tests cover the sessionFenceRewriteIsBenign rewrite-with-new-inode scenario
  • TypeScript compiles cleanly with the change
  • Manual verification: restart OpenClaw and observe bot processes messages without EmbeddedAttemptSessionTakeoverError

Fix branch: raymondjxj/fix/session-fence-compaction-false-positive
File changed: src/agents/embedded-agent-runner/run/attempt.session-lock.ts

…ce check

sessionFenceRewriteIsBenign rejected all rewrites where the file inode
changed, even when content validation passed. When compaction rewrites
the session file (new inode, smaller size), the early
sameSessionFileIdentity check caused both benign-check functions to
return false, triggering a false-positive EmbeddedAttemptSessionTakeoverError.

Fix: remove sameSessionFileIdentity from the early-return guard in
sessionFenceRewriteIsBenign. The function already rigorously validates
content via lineMatchesLinearTranscriptMigration. When content validation
passes, the rewrite is safe regardless of whether the inode changed —
a compaction rewrite with new inode is benign.
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 30, 2026
@clawsweeper

clawsweeper Bot commented May 30, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

This PR should close because the same compaction false-positive was fixed by the merged, narrower #90775 path, which trusts only owned SessionManager.appendCompaction(...) writes and keeps generic replacement-file rewrites rejected.

Canonical path: Keep the shipped owned-compaction persistence implementation from #90775 and close this broader replacement-file whitelist branch as superseded.

So I’m closing this here and keeping the remaining discussion on #90775.

Review details

Best possible solution:

Keep the shipped owned-compaction persistence implementation from #90775 and close this broader replacement-file whitelist branch as superseded.

Do we have a high-confidence way to reproduce the issue?

Yes. The pre-fix path is clear from source and the merged replacement PR documented before/after Testbox proof; current main no longer reproduces the false takeover for owned compaction because it records the guarded compaction write.

Is this the best way to solve the issue?

No. This branch is broader than necessary; the best fix is the already-merged owned compaction persistence hook with negative coverage for external edits.

Security review:

Security review needs attention: The proposed branch weakens a session takeover boundary by trusting different-inode replacement files based on content shape alone.

  • [medium] Replacement file can bypass takeover provenance — src/agents/embedded-agent-runner/run/attempt.session-lock.ts:339
    Dropping the identity guard allows a different inode to be accepted when the JSONL contents look benign, which is broader than the owned compaction provenance used by current main.
    Confidence: 0.9

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • @jalehman: Authored and landed the merged PR that fixes owned compaction prompt-fence refresh while preserving external edit rejection. (role: canonical fix author; confidence: high; commits: bbfe8ccaf60e, 054ea49f5754; files: src/agents/embedded-agent-runner/run/attempt.session-lock.ts, src/agents/embedded-agent-runner/run/attempt.ts, src/agents/session-tool-result-guard.ts)
  • @vincentkoc: Current checkout blame for the session-lock and guard lines points to this maintainer-area commit, and the inspected release tag was created by the same person. (role: recent current-main committer and release tagger; confidence: medium; commits: 40093f5a93ed, 8c802aa68351; files: src/agents/embedded-agent-runner/run/attempt.session-lock.ts, src/agents/session-tool-result-guard.ts)
  • @byungskers: Raised the same safety concern on this PR: accepting different-inode replacement files by content alone is broader than trusting owned compaction provenance. (role: review commenter; confidence: medium; files: src/agents/embedded-agent-runner/run/attempt.session-lock.ts)

Codex review notes: model internal, reasoning high; reviewed against 1db8ab373422; fix evidence: release v2026.6.6, commit bbfe8ccaf60e.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels May 30, 2026
@byungskers

Copy link
Copy Markdown

I don't think the new-inode acceptance is safe in this shape. Dropping sameSessionFileIdentity(...) means any replacement file that preserves the prior prefix and appends OpenClaw-looking assistant lines can now pass the benign-rewrite path, even if it was not produced by the owned compaction/write flow. If the real issue is a compaction-specific rewrite, I'd be more comfortable proving that exact path and tying the exception to owned/trusted compaction provenance rather than accepting all content-valid replacement files.

@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper applied the proposed close for this PR.

@clawsweeper clawsweeper Bot closed this Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants