#22465: fix: preserve session history after API error (400/503) in mid-conversation
agents
size: XS
Cluster:
Error Handling in Agent Tools
## Problem
When an API error (400/503) occurs mid-conversation, the session transcript already contains the user's message (written by the SDK before the error), but has no assistant reply. On the next turn, `prepareSessionManagerForRun` in `session-manager-init.ts` detects `!hasAssistant` and **resets the entire session file**, wiping all prior conversation history. The user is forced to run `/compact` to recover.
## Root Cause
`session-manager-init.ts` line 44 had the condition:
```ts
if (params.hadSessionFile && header && !hasAssistant)
```
This was intended to reset **pre-created empty session files** (header only, no messages yet). However, it also incorrectly matched sessions that had a full conversation history but ended with an orphaned user message due to an API error.
## Fix
Added a `hasUser` check so the reset only fires when there are **no user messages** in the session (i.e. a truly empty pre-created file):
```ts
if (params.hadSessionFile && header && !hasAssistant && !hasUser)
```
If `hasUser` is true, the session already has conversation history — the orphaned trailing user message is handled by the existing repair logic in `attempt.ts` (lines 983–1000) on the next prompt call.
## Impact
- All channels affected (Telegram, Slack, Discord, iMessage, Web, etc.)
- After a 400/503 API error, conversation history is now preserved
- The next message continues the conversation normally without requiring `/compact`
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Targeted one-line fix in `session-manager-init.ts` that adds a `!hasUser` guard to the session-reset condition. Previously, `prepareSessionManagerForRun` would wipe the entire session file when `hadSessionFile && header && !hasAssistant` was true — this incorrectly matched sessions where the first user turn hit an API error (400/503), leaving a user message but no assistant reply. By also requiring `!hasUser`, the reset now only fires for truly empty pre-created session files (header only, no messages). Sessions with conversation history are preserved, and the existing orphaned-user-message repair in `attempt.ts` (lines 983–1000) handles recovery on the next prompt.
- Condition in `prepareSessionManagerForRun` tightened from `!hasAssistant` to `!hasAssistant && !hasUser`
- New `hasUser` variable mirrors the existing `hasAssistant` check pattern
- Well-documented with inline comments and an updated JSDoc note
- No test coverage added for this function (none existed previously either)
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge — it's a minimal, well-scoped condition tightening that preserves existing behavior for all previously-handled cases and only changes the outcome for the specific bug scenario.
- The change is a single additional boolean guard (`!hasUser`) on an existing condition. The new `hasUser` variable follows the exact same pattern as the existing `hasAssistant` check. The fix correctly narrows the reset to truly empty sessions, while deferring orphaned-user-message recovery to the existing repair logic in `attempt.ts:983-1000`, which I verified handles the case properly. The change is logically sound and cannot regress any previously-working scenario (sessions with assistant messages were already excluded; sessions without any messages still get reset; the only new exclusion is sessions with user messages but no assistant messages, which is the bug scenario).
- No files require special attention
<sub>Last reviewed commit: 7deee92</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#14328: fix: strip incomplete tool_use blocks from errored/aborted messages...
by Kropiunig · 2026-02-12
80.1%
#17743: fix(agents): disable orphaned user message deletion that causes ses...
by clawrl3000 · 2026-02-16
79.6%
#13104: fix: persist user command message in chat transcript
by mcaxtr · 2026-02-10
78.8%
#22433: Slack: fix thread context loss after session reset
by stgarrity · 2026-02-21
78.3%
#21828: fix: acquire session write lock in delivery mirror and gateway chat...
by inkolin · 2026-02-20
78.2%
#15050: fix: transcript corruption resilience — strip aborted tool_use bloc...
by yashchitneni · 2026-02-12
78.1%
#6653: fix: persist archived session entry on /new or /reset
by leicao-me · 2026-02-01
77.0%
#16061: fix(sessions): tolerate invalid sessionFile metadata
by haoyifan · 2026-02-14
77.0%
#7537: fix(sessions): reset token counts on /new for channel sessions
by SoniAssist · 2026-02-02
76.8%
#9085: fix: improve stability for terminated responses and telegram retries
by vladdick88 · 2026-02-04
76.5%