fix(embedded-agent-runner): false positive EmbeddedAttemptSessionTakeoverError during session compaction#88348
Conversation
…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.
|
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 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 detailsBest 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.
AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against 1db8ab373422; fix evidence: release v2026.6.6, commit bbfe8ccaf60e. |
|
I don't think the new-inode acceptance is safe in this shape. Dropping |
|
ClawSweeper applied the proposed close for this PR.
|
Bug Summary
Error:
EmbeddedAttemptSessionTakeoverError: session file changed while embedded prompt lock was releasedSymptom: OpenClaw bot stops processing messages, repeating
lane task error+Embedded agent failed before replyRoot 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 setsfenceActive = 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 callsassertSessionFileFence(), the fence check fails because:sessionFenceRewriteIsBenignhassameSessionFileIdentity()(inode comparison) as its first guard condition (line 266)sameSessionFileIdentityreturnsfalse→ function returnsfalseimmediately without reaching content validationsessionFenceAdvanceIsBenignandsessionFenceRewriteIsBenignreturnfalseEmbeddedAttemptSessionTakeoverErroris thrown (false positive)The Fix
Remove
sameSessionFileIdentity()from the early-return guard insessionFenceRewriteIsBenign. The function already rigorously validates content vialineMatchesLinearTranscriptMigration+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
returnstatement becomes a content-check +true:Why This Is Safe
The
lineMatchesLinearTranscriptMigration+isTranscriptOnlyOpenClawAssistantLinecontent validation rigorously confirms: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
releaseForPrompt()releases write lock (to allow streaming)~/.openclaw/agents/ling/sessions/{session-id}.jsonlreacquireAfterPrompt()detects file changed → throwsEmbeddedAttemptSessionTakeoverErrorlane task error+Embedded agent failed before replyTesting
sessionFenceRewriteIsBenignrewrite-with-new-inode scenarioEmbeddedAttemptSessionTakeoverErrorFix branch:
raymondjxj/fix/session-fence-compaction-false-positiveFile changed:
src/agents/embedded-agent-runner/run/attempt.session-lock.ts