Skip to content

fix(sessions): reply session init fails under rapid consecutive turns#99048

Closed
rushitgit wants to merge 3 commits into
openclaw:mainfrom
rushitgit:fix/reply-session-init-retry-budget
Closed

fix(sessions): reply session init fails under rapid consecutive turns#99048
rushitgit wants to merge 3 commits into
openclaw:mainfrom
rushitgit:fix/reply-session-init-retry-budget

Conversation

@rushitgit

@rushitgit rushitgit commented Jul 2, 2026

Copy link
Copy Markdown

What Problem This Solves

Rapid consecutive turns on the same reply session can hit reply session initialization conflicted when the session-store revision advances between snapshot and commit more than once. The previous code retried one stale snapshot, then surfaced the error to the user.

Change

Replace the boolean stale-snapshot retry flag with a bounded attempt counter. The retry budget is now 4 total attempts.

The snapshot, commit, locking, and final failure behavior are unchanged. This only gives transient same-session revision conflicts a small bounded retry window.

Evidence

Pre-fix TUI observation, redacted:

session: agent:main:tui-b309...83a6
instagram.com curl: 301
rapid same-session follow-ups: polymarkets.com, this, hi please come alive
observed: Error: reply session initialization conflicted for agent:main:tui-b309...83a6

Post-fix runtime proof on this PR head:

branch: fix/reply-session-init-retry-budget
head: 6d5cce63
cli: OpenClaw 2026.6.11 (6d5cce6)
proof session: agent:main:tui-a228...f259
command shape: three immediate same-session openclaw agent --session-key <proof-session> --message ... --json turns

status_a=0
status_b=0
status_c=0
turn_A status=ok text='OK A' sessionId=b917...208 model=openai/gpt-5.4
turn_B status=ok text='OK B' sessionId=b917...208 model=openai/gpt-5.4
turn_C status=ok text='OK C' sessionId=b917...208 model=openai/gpt-5.4

Target error check for the post-fix run:

No `reply session initialization conflicted` error occurred during the post-fix proof run.

Added src/auto-reply/reply/session-init-retry-budget.test.ts. It uses the real file-backed loadReplySessionInitializationSnapshot and commitReplySessionInitialization functions and induces the same 3-writer revision-conflict burst against agent:main:main.

old budget (2 attempts) throws under a 3-writer burst
new budget (4 attempts) succeeds under the identical 3-writer burst

Checked locally:

npx vitest run src/auto-reply/reply/session-init-retry-budget.test.ts src/auto-reply/reply/session.test.ts extensions/telegram/src/polling-session.test.ts
Test Files  3 passed (3)
Tests       201 passed (201)

npx oxlint src/auto-reply/reply/session.ts src/auto-reply/reply/session-init-retry-budget.test.ts
npx oxfmt --check src/auto-reply/reply/session.ts src/auto-reply/reply/session-init-retry-budget.test.ts

npx tsc --noEmit -p tsconfig.core.json has no new errors. The existing TS4058 in src/secrets/config-io.ts reproduces on main.

Notes

This is a small mitigation for transient same-session write races. It does not replace the related root-cause work in #98416 or #98835.

@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 2, 2026, 9:47 AM ET / 13:47 UTC.

Summary
The PR increases reply-session initialization from one stale-snapshot retry to four total attempts and adds a file-backed retry-budget regression test.

PR surface: Source +2, Tests +103. Total +105 across 2 files.

Reproducibility: yes. for the source path: current main retries one stale snapshot and then throws, while the PR and related reports show the same conflict family under rapid same-session turns. I did not run a fresh current-main live repro in this read-only review.

Review metrics: 1 noteworthy metric.

  • Retry budget changed: 2 -> 4 total attempts. This is the user-facing runtime behavior change and affects how long shared session initialization tolerates stale-revision conflicts before surfacing an error.

Stored data model
Persistent data-model change detected: serialized state: src/auto-reply/reply/session-init-retry-budget.test.ts, serialized state: src/auto-reply/reply/session.ts, unknown-data-model-change: src/auto-reply/reply/session-init-retry-budget.test.ts, unknown-data-model-change: src/auto-reply/reply/session.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🐚 platinum hermit
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Tie the regression test to the production initSessionState retry path.

Risk before merge

  • [P1] The retry budget changes shared reply-session initialization behavior across channels, so maintainers should confirm this bounded mitigation should ship alongside or ahead of the broader session-accessor work in fix(config/sessions): narrow reply-session initialization revision to identity fields #98835.
  • [P1] The new regression test does not fail if the production retry loop remains at the old one-retry behavior, leaving the main changed path under-covered.

Maintainer options:

  1. Tie coverage to production retrying (recommended)
    Update the regression test so reverting the initSessionState retry-budget change fails, then rerun the focused session tests before merge.
  2. Land as an explicit mitigation
    Maintainers can accept the coverage gap if they want this narrow retry budget urgently and keep the broader root-cause work tracked separately.
  3. Pause behind the broader fix
    Pause or close this PR if maintainers prefer to resolve the session-accessor root cause in fix(config/sessions): narrow reply-session initialization revision to identity fields #98835 before adding an extra retry budget.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Tie the reply-session retry-budget regression test to the production initSessionState retry path so the test fails if session.ts keeps or reverts to the old one-retry behavior; keep the runtime behavior unchanged except for any minimal test seam needed, then run the focused session tests.

Next step before merge

  • [P2] A narrow test repair remains and the branch allows maintainer edits, so an automated follow-up can try to bind coverage to the production retry path.

Security
Cleared: The diff only changes TypeScript session retry logic and a colocated test; no dependency, workflow, secret, package, or code-execution surface change was found.

Review findings

  • [P2] Tie retry-budget coverage to the production loop — src/auto-reply/reply/session-init-retry-budget.test.ts:11-17
Review details

Best possible solution:

Keep the bounded retry mitigation, but land it only after the regression coverage is tied to the production retry path and maintainers accept it as a companion to the broader session-conflict fixes.

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

Yes for the source path: current main retries one stale snapshot and then throws, while the PR and related reports show the same conflict family under rapid same-session turns. I did not run a fresh current-main live repro in this read-only review.

Is this the best way to solve the issue?

No, not quite as submitted. The bounded retry is an acceptable mitigation with now-sufficient real-output proof, but the regression test should exercise or bind to the production retry loop before this is the best merge shape.

Full review comments:

  • [P2] Tie retry-budget coverage to the production loop — src/auto-reply/reply/session-init-retry-budget.test.ts:11-17
    The new test recreates the retry loop in initSessionWithBudget with a caller-supplied maxAttempts, so it still passes if initSessionState keeps or reverts to the old one-retry behavior. Drive initSessionState or otherwise bind the test to the production retry budget so this regression coverage fails when the runtime change is absent.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 0ccdef5dcf76.

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The contributor added redacted copied live output from three immediate same-session CLI turns on this PR head, all succeeding without the target conflict error.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🐚 platinum hermit and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The contributor added redacted copied live output from three immediate same-session CLI turns on this PR head, all succeeding without the target conflict error.
  • remove rating: 🧂 unranked krab: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.
  • remove status: 📣 needs proof: Current PR status label is status: ⏳ waiting on author.

Label justifications:

  • P1: The PR targets a user-facing reply-session conflict that can break rapid chat or channel turns for real users.
  • merge-risk: 🚨 session-state: The diff changes guarded retry behavior in shared reply-session initialization, which decides when session-state writes fail or are retried.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🐚 platinum hermit and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The contributor added redacted copied live output from three immediate same-session CLI turns on this PR head, all succeeding without the target conflict error.
  • proof: sufficient: Contributor real behavior proof is sufficient. The contributor added redacted copied live output from three immediate same-session CLI turns on this PR head, all succeeding without the target conflict error.
Evidence reviewed

PR surface:

Source +2, Tests +103. Total +105 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 9 7 +2
Tests 1 103 0 +103
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 112 7 +105

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/auto-reply/reply/session-init-retry-budget.test.ts src/auto-reply/reply/session.test.ts.
  • [P1] node scripts/run-vitest.mjs src/config/sessions/session-accessor.test.ts.
  • [P1] pnpm exec oxfmt --check --threads=1 src/auto-reply/reply/session.ts src/auto-reply/reply/session-init-retry-budget.test.ts.
  • [P1] node scripts/run-oxlint.mjs src/auto-reply/reply/session.ts src/auto-reply/reply/session-init-retry-budget.test.ts.

What I checked:

  • Root review policy applied: Root AGENTS.md was read fully; its ClawSweeper policy treats session state and reply-path changes as compatibility-sensitive and requires whole-path review beyond the diff. (AGENTS.md:18, 0ccdef5dcf76)
  • No scoped AGENTS for touched paths: The scoped-guide search found AGENTS.md files under other src subtrees but none under src/auto-reply or src/config/sessions for this PR's touched files. (0ccdef5dcf76)
  • Current main retry behavior: Current main calls initSessionStateAttempt(params, false) and throws after one retry when commitReplySessionInitialization keeps returning a stale snapshot, so this PR is not already implemented on main. (src/auto-reply/reply/session.ts:312, 0ccdef5dcf76)
  • Runtime entry point: Normal reply handling reaches the changed initializer through the reply.init_session_state phase in get-reply.ts, making the retry budget shared reply-path behavior. (src/auto-reply/reply/get-reply.ts:476, 0ccdef5dcf76)
  • Session-accessor conflict contract: commitReplySessionInitialization returns reason: "stale-snapshot" when the persisted revision differs and uses reentrant session-store writes on current main. (src/config/sessions/session-accessor.ts:1762, 0ccdef5dcf76)
  • PR runtime change: The PR head adds MAX_SESSION_INIT_ATTEMPTS = 4 and uses an attempt counter before throwing the same conflict error. (src/auto-reply/reply/session.ts:310, 6d5cce6331cf)

Likely related people:

  • joshavant: Authored and merged the persisted-shape reply-init revision fix in the same session-accessor/test boundary, and local blame currently routes the init retry branch through recent session-file history. (role: recent session-accessor contributor; confidence: high; commits: 75db48a17522; files: src/config/sessions/session-accessor.ts, src/config/sessions/session-accessor.test.ts, src/auto-reply/reply/session.ts)
  • obviyus: Authored and merged the reply-session writer-lane serialization and reentrant store-writer support that the retry path depends on. (role: adjacent session writer-lane contributor; confidence: high; commits: d2da8c79d9b8; files: src/auto-reply/reply/session.ts, src/config/sessions/store-writer.ts, src/shared/store-writer-queue.ts)
  • VACInc: Authored the merged Telegram spool backoff for the same retryable reply-session initialization conflict string in channel ingestion. (role: adjacent channel retry contributor; confidence: medium; commits: d8d6f9498509; files: extensions/telegram/src/polling-session.ts, extensions/telegram/src/polling-session.test.ts, extensions/telegram/src/telegram-ingress-spool.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Reply session initialization commits a revision-guarded write and
retried exactly once on conflict before throwing "reply session
initialization conflicted for <sessionKey>". Under bursts of rapid
consecutive turns on the same session (e.g. several quick messages
sent back to back before the prior turn's session-state write
settles), a single retry was not always enough, surfacing the error
directly to end users even though a subsequent attempt — reading a
fresh, correctly-serialized snapshot — would very likely succeed.

Raise the retry ceiling from 1 retry to a small bounded budget
(4 total attempts) so this transient contention is absorbed
transparently, while still throwing if the store is genuinely stuck
after exhausting the budget. No change to locking, snapshot, or
commit semantics — only the retry count.

Co-authored-by: Cursor <[email protected]>
@rushitgit
rushitgit force-pushed the fix/reply-session-init-retry-budget branch from 852355f to 00b8d39 Compare July 2, 2026 10:44
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. 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. labels Jul 2, 2026
Exercises the real session-accessor commit/snapshot functions under an
induced 3-writer revision-conflict burst, proving the old 2-attempt
ceiling throws and the new 4-attempt ceiling absorbs the same race.

Co-authored-by: Cursor <[email protected]>
@openclaw-barnacle openclaw-barnacle Bot added size: S triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. and removed size: XS labels Jul 2, 2026
Remove non-essential explanatory comments from the retry-budget change and regression test.

Co-authored-by: Cursor <[email protected]>
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 2, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jul 2, 2026
@rushitgit

Copy link
Copy Markdown
Author

@clawsweeper re-review

Additional real behavior proof, redacted.

Pre-fix user-visible TUI proof:

  • Affected setup: OpenClaw TUI, session agent:main:tui-b309...83a6.
  • Sequence shown in screenshot: a curl request to instagram.com returned 301; immediate follow-up turns to the same TUI session (polymarkets.com, this, hi please come alive) then surfaced repeated user-visible errors.
  • Observed error: Error: reply session initialization conflicted for agent:main:tui-b309...83a6.

Post-fix runtime proof on this PR head:

  • Branch: fix/reply-session-init-retry-budget
  • Head: 6d5cce63
  • CLI: OpenClaw 2026.6.11 (6d5cce6)
  • Gateway status before proof: reachable local gateway running the same branch/head.
  • Proof session: agent:main:tui-a228...f259
  • Command shape: three immediate same-session openclaw agent --session-key <proof-session> --message ... --json turns.

Observed post-fix result:

status_a=0
status_b=0
status_c=0
turn_A status=ok text='OK A' sessionId=b917...208 model=openai/gpt-5.4
turn_B status=ok text='OK B' sessionId=b917...208 model=openai/gpt-5.4
turn_C status=ok text='OK C' sessionId=b917...208 model=openai/gpt-5.4

Target error check:

No `reply session initialization conflicted` error occurred during the post-fix proof run.

Focused code proof is also included in src/auto-reply/reply/session-init-retry-budget.test.ts: old 2-attempt budget throws under a 3-writer stale-snapshot burst; new 4-attempt budget succeeds under the identical burst using the real file-backed session-accessor functions.

@clawsweeper

clawsweeper Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed 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. labels Jul 2, 2026
@jalehman

jalehman commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Closing this as superseded by #98835, which has now landed as 826c84e.

#98835 fixes the shared false-conflict predicate at the session-accessor commit boundary rather than increasing the retry budget: same-session metadata drift is accepted, while real session identity changes remain guarded. That head passed the real behavior proof lane plus the session-accessor boundary and full relevant hosted CI before merge.

This PR was useful as a mitigation candidate, but it still had an open coverage finding and is no longer the best fix now that the root session initialization fix is on main. If a distinct rapid-turn conflict still reproduces on current main after 826c84e, please open or refresh an issue with current-main logs and behavior proof. Published package parity remains tracked separately in #98416.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants