Skip to content

fix(gateway): log errors when terminal persistence rejects in chat-abort cleanup#97813

Closed
SunnyShu0925 wants to merge 0 commit into
openclaw:mainfrom
SunnyShu0925:fix/chat-abort-persistence-log-97795
Closed

fix(gateway): log errors when terminal persistence rejects in chat-abort cleanup#97813
SunnyShu0925 wants to merge 0 commit into
openclaw:mainfrom
SunnyShu0925:fix/chat-abort-persistence-log-97795

Conversation

@SunnyShu0925

@SunnyShu0925 SunnyShu0925 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Related to #97795.

What Problem This Solves

persistGatewaySessionLifecycleEvent failures in createAgentEventHandler are silently swallowed — the terminal lifecycle handler catches rejection only to broadcast a fallback session snapshot, without logging the failure. Operators cannot observe session-store write failures in production.

Why This Change Was Made

Log the rejected persistence at the owner boundary (server-chat.ts) where the promise is created and its rejection is already caught for fallback projection. This is the single correct site — it owns both the persistence promise and the fallback projection. Logging in cleanup consumers (chat-abort.ts, server-runtime-subscriptions.ts) would be downstream duplicates that miss the owner/fallback case and risk double-reporting.

A module-level createSubsystemLogger("gateway/server-chat") follows the established gateway pattern.

Root Cause

introduced by commit 7c47904bb42d (joshavant). The original owner catch only broadcast a fallback session snapshot; it never logged the write failure.

Confidence: clear — the .catch(() => { broadcastSessionChange(evt); }) handler visibly omits error recording.

User Impact

None — this is an observability fix for operators.

Evidence

Behavior addressed: When persistGatewaySessionLifecycleEvent rejects, the gateway logs the failure with the run ID and error before broadcasting the fallback session snapshot. Logging happens once at the persistence owner boundary.

Real environment tested: Linux (kernel 4.19), Node v22, branch fix/chat-abort-persistence-log-97795 (HEAD 803e4d5499), based on origin/main 68ead4dd80.

Exact steps or command run after this patch:

$ node scripts/run-oxlint.mjs src/gateway/server-chat.ts src/gateway/server-chat.agent-events.test.ts
EXIT=0

$ npx oxfmt --check src/gateway/server-chat.ts src/gateway/server-chat.agent-events.test.ts
All matched files use the correct format.

Evidence after fix:

Persistence outcome Before After
persistGatewaySessionLifecycleEvent resolves markPersisted() + broadcast (existing) unchanged
persistGatewaySessionLifecycleEvent rejects silent fallback broadcast only log.error → then fallback broadcast

Test output — assertion added to existing fallback test:

$ npx vitest run src/gateway/server-chat.agent-events.test.ts --reporter=verbose

 ✓ |gateway-server| agent event handler > broadcasts a terminal fallback snapshot when persistence fails  5ms
 ✓ |gateway-server| agent event handler > does not clear a same-id retry when an old restart terminal arrives  3ms
 ✓ |gateway-server| agent event handler > ...

 Test Files  1 passed (1)
      Tests  95 passed (95)
   Duration  10.24s

The existing test "broadcasts a terminal fallback snapshot when persistence fails" now additionally asserts mockLogError was called with "gateway: failed to persist terminal session lifecycle event for run run-failed-write: Error: disk full".

Observed result after fix: When persistGatewaySessionLifecycleEventMock rejects with new Error("disk full"), the owner catch logs the error via log.error and still broadcasts the fallback sessions.changed snapshot. The markTrackedRunTerminalPersisted callback is still not called (persistence failed). All 95 existing tests pass.

What was not tested:

  • Forcing an actual disk write failure in a live gateway session store — the vitest suite exercises the real createAgentEventHandler production code and asserts the log is emitted from the exact same .catch() block that the compiled gateway runs

Regression Test Plan

$ npx vitest run src/gateway/server-chat.agent-events.test.ts --reporter=verbose

 Test Files  1 passed (1)
      Tests  95 passed (95)

Modified test broadcasts a terminal fallback snapshot when persistence fails:

  1. persistGatewaySessionLifecycleEventMock rejects with new Error("disk full")
  2. Send terminal lifecycle event via handler({...})
  3. Assert fallback sessions.changed broadcast (existing)
  4. Assert mockLogError called with message containing run ID and error text (new)

Changes

  • src/gateway/server-chat.ts: +8/−1 lines — createSubsystemLogger import, module-level logger, log.error in the persistence owner .catch()
  • src/gateway/server-chat.agent-events.test.ts: +11 lines — vi.mock for logging subsystem, mockLogError assertion in the existing fallback snapshot test

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: XS labels Jun 29, 2026
@clawsweeper

clawsweeper Bot commented Jun 29, 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 has the right owner-boundary idea, but it is now superseded by an open sibling that targets the same server-chat.ts catch, uses the gateway formatter for unknown errors, and includes stronger real-runtime proof.

Root-cause cluster
Relationship: superseded
Canonical: #97839
Summary: This PR and the sibling PRs address the same rejected terminal persistence logging gap; the open canonical sibling is the safer owner-boundary landing candidate because it uses gateway formatting and has stronger proof.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Close this branch and review the formatted, proof-positive owner-boundary implementation in https://github.com/openclaw/openclaw/pull/97839 as the canonical fix for https://github.com/openclaw/openclaw/issues/97795.

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

Review details

Best possible solution:

Close this branch and review the formatted, proof-positive owner-boundary implementation in https://github.com/openclaw/openclaw/pull/97839 as the canonical fix for https://github.com/openclaw/openclaw/issues/97795.

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

Yes. Source inspection shows a rejected persistGatewaySessionLifecycleEvent reaches the current-main owner catch, which only broadcasts fallback sessions.changed state and does not log the failed write.

Is this the best way to solve the issue?

No. The owner-boundary location is the right fix shape, but this branch is no longer the best landing path because the sibling PR uses formatForLog(err) and includes stronger real-runtime proof.

Security review:

Security review needs attention: The diff adds a low-severity log-boundary concern by rendering unknown persistence errors without the gateway formatter.

  • [low] Unknown rejection bypasses gateway formatter — src/gateway/server-chat.ts:716
    The new log message formats an arbitrary rejected value with String(err) instead of formatForLog(err), weakening gateway redaction and length-capping for persistence errors.
    Confidence: 0.86

AGENTS.md: found and applied where relevant.

What I checked:

  • Repository policy read: Root and scoped gateway AGENTS.md were read fully; the review applied the gateway owner-boundary, proof, and security guidance. (AGENTS.md:1, 6de357ad4772)
  • Current main still has the silent owner catch: Current main creates and tracks persistGatewaySessionLifecycleEvent, then catches rejection only to broadcast a fallback session snapshot without logging the failed write. (src/gateway/server-chat.ts:719, 6de357ad4772)
  • This PR logs raw unknown rejection text: The PR adds a log.error call at the owner catch, but renders the unknown rejection with String(err). (src/gateway/server-chat.ts:716, 803e4d5499d0)
  • Gateway formatter contract: formatForLog is the existing gateway helper for formatting, redacting, and capping arbitrary values before gateway logs. (src/gateway/ws-log.ts:114, 6de357ad4772)
  • Canonical sibling is a better landing path: The open sibling PR uses formatForLog(err) at the same owner catch, adds a redaction assertion, and its body includes copied real runtime EPERM proof plus fallback sessions.changed output. (src/gateway/server-chat.ts:717, f3abe1365048)
  • Related work cluster: GitHub search and live PR views show the open issue and multiple overlapping PRs; https://github.com/openclaw/openclaw/pull/97839 is the focused owner-boundary branch, while the other open cleanup-consumer branches overlap the same report.

Likely related people:

  • Alix-007: Current checkout blame for the terminal persistence owner catch and sibling cleanup paths points to 5f86c3a90f69e; confidence is low because the commit title is not gateway-specific. (role: current line provenance; confidence: low; commits: 5f86c3a90f69; files: src/gateway/server-chat.ts, src/gateway/chat-abort.ts, src/gateway/server-runtime-subscriptions.ts)
  • openperf: Merged gateway lifecycle persistence work around persistGatewaySessionLifecycleEvent is directly adjacent to the rejected persistence path being logged here. (role: adjacent lifecycle persistence contributor; confidence: medium; commits: 613f51a7aa91; files: src/gateway/session-lifecycle-state.ts, src/gateway/session-lifecycle-state.test.ts)
  • steipete: Adjacent stale lifecycle snapshot work and PR search results tie this person to the same gateway session lifecycle persistence surface. (role: adjacent lifecycle persistence contributor; confidence: medium; commits: ec13a2873cf9; files: src/gateway/session-lifecycle-state.ts, src/gateway/session-lifecycle-state.test.ts)
  • Jordan Baker: Authored nearby gateway/runtime error-detail formatting work, which is relevant because the blocking issue is how unknown errors are rendered at the gateway log boundary. (role: adjacent formatter contributor; confidence: low; commits: 86c1622a3a3c; files: src/gateway/ws-log.ts, src/gateway/ws-log.test.ts)

Codex review notes: model internal, reasoning high; reviewed against 6de357ad4772.

@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. P2 Normal backlog priority with limited blast radius. 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 Jun 29, 2026
@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 29, 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.

@SunnyShu0925
SunnyShu0925 force-pushed the fix/chat-abort-persistence-log-97795 branch from 87f37e8 to 4d29d9b Compare June 29, 2026 15:17
@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. and removed 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. labels Jun 29, 2026
@SunnyShu0925
SunnyShu0925 force-pushed the fix/chat-abort-persistence-log-97795 branch from 4d29d9b to 803e4d5 Compare June 29, 2026 15:39
@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 29, 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.

@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@SunnyShu0925

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper could not start a re-review for this item.

Reason: re-review requires an open issue or PR.

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

Labels

gateway Gateway runtime merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants