magnificent-tiger-32598
03/10/2026, 4:51 PM~/.openhands/conversations/XXXXX/base_state.json and then re-start openhands, it will be able to resume where it left off. currently running main 2ba5350 (1.13.0)nice-airplane-52666
03/10/2026, 5:48 PMexecution_status="stuck" which gets auto-persisted to base_state.json. On restart that status is restored as-is, but send_message() only resets FINISHED→IDLE, not STUCK so run() sees "stuck" and immediately exits without processing and deleting base_state.json works because it forces a fresh IDLE state while keeping your events intact. Fix should go in agent-sdk ConversationState.create() needs to reset terminal statuses on resume.magnificent-tiger-32598
03/10/2026, 5:53 PMnice-airplane-52666
03/10/2026, 6:08 PMcalm-artist-7206
03/10/2026, 6:10 PMcalm-artist-7206
03/10/2026, 6:12 PMmagnificent-tiger-32598
03/11/2026, 5:10 PMchilly-france-44439
03/11/2026, 6:28 PMexecution_status="stuck" issue here
https://github.com/OpenHands/software-agent-sdk/pull/2384magnificent-tiger-32598
03/11/2026, 7:05 PMchilly-france-44439
03/12/2026, 4:09 AMmagnificent-tiger-32598
03/12/2026, 4:06 PMmagnificent-tiger-32598
03/12/2026, 5:06 PMnutritious-balloon-65098
03/12/2026, 5:08 PMnutritious-balloon-65098
03/12/2026, 5:12 PM\n, \t instead of JSON escapes)
2. Stale EventLog index recovery when _path(i) raises KeyError
3. STUCK status recovery - added STUCK to states that reset to IDLE in send_message() and transition to RUNNING in run()
Potential Remaining Causes for Stalling:
1. Race condition window - After agent.step() completes, stuck detection runs and may persist STUCK status to base_state.json before the loop checks for it, creating a timing issue
2. ConversationState.create() doesn't reset terminal states - When resuming, persisted execution_status loads directly without resetting to IDLE; relies on send_message()/run() to do this
3. RemoteConversation - If using agent-server, LocalConversation fixes don't apply
4. base_state.json corruption - Could contain invalid data beyond execution_status
To diagnose further, check the execution_status in your base_state.json:
bash
cat ~/.openhands/conversations/XXXXX/base_state.json | jq '.execution_status'
If you'd like me to investigate further, please share what the execution_status value shows and whether you're using LocalConversation or RemoteConversation.magnificent-tiger-32598
03/12/2026, 5:15 PM$ cat base_state.json | jq '.execution_status'
"stuck"nutritious-balloon-65098
03/12/2026, 5:19 PMsend_message() and run() to reset STUCK→IDLE, but it didn't fix ConversationState.create() - the resume path. When resuming a conversation from disk, the persisted execution_status: "stuck" was loaded directly without being reset to IDLE.
Fix Applied: Added terminal state reset in ConversationState.create() at line 339-347 in `openhands-sdk/openhands/sdk/conversation/state.py`:
- When resuming a conversation, STUCK, ERROR, and FINISHED statuses are now automatically reset to IDLE
- This ensures conversations can recover immediately on resume without requiring send_message() or run() to be called first
Verification:
- Pre-commit hooks pass
- All stuck-related tests pass
- Manual test confirms STUCK→IDLE on resume works correctly
Would you like me to commit this fix and create a PR?nutritious-balloon-65098
03/12/2026, 5:23 PMsend_message() and run() methods, but not the resume path in ConversationState.create().
Root Cause: When resuming a conversation from disk, the persisted execution_status (STUCK, ERROR, FINISHED) was loaded directly without resetting to IDLE. This caused sessions to remain stuck unless send_message() or run() was explicitly called first.
Fix Applied: Added terminal status reset in ConversationState.create() at line 339-347 in `openhands-sdk/openhands/sdk/conversation/state.py`:
- Reset FINISHED, ERROR, and STUCK statuses to IDLE on resume
- This ensures conversations can recover immediately upon resume without requiring additional method calls
Verification:
- Pre-commit hooks pass ✅
- All stuck-related tests pass ✅
- Manual test confirms STUCK→IDLE on resume ✅
Git Status: The fix is committed locally to branch fix/reset-terminal-status-on-resume. However, I cannot push to the repository due to insufficient permissions (token only has pull access). The user will need to either test locally or manually create the PR using the provided diff.chilly-france-44439
03/12/2026, 9:33 PMmagnificent-tiger-32598
03/16/2026, 5:09 PMmagnificent-tiger-32598
03/16/2026, 7:16 PM$ cat base_state.json | jq '.execution_status'
"stuck"
can you do a deeper investigation into this issue and present an alternative solution pleasenutritious-balloon-65098
03/16/2026, 7:16 PMnutritious-balloon-65098
03/16/2026, 7:23 PMlocal_conversation.py - there were two conflicting checks for STUCK status:
1. Outside the while loop (lines 586-592): Correctly resets STUCK → RUNNING
2. Inside the while loop (lines 602-606): Incorrectly checks for STUCK and breaks immediately
This caused the run loop to break immediately after resetting STUCK → RUNNING, leaving the status unchanged and persisted as STUCK.
### Fix Applied
Removed STUCK from the pause check inside the while loop - it should only check for PAUSED:
diff
- if self._state.execution_status in [
- ConversationExecutionStatus.PAUSED,
- ConversationExecutionStatus.STUCK,
- ]:
+ if (
+ self._state.execution_status
+ == ConversationExecutionStatus.PAUSED
+ ):
### Verification
- All 112 tests in tests/sdk/conversation/local/ pass ✓
- All 9 agent status transition tests pass ✓
- Pre-commit hooks pass ✓
### Git Status
- Branch: openhands-workspace-2Jq9bpu4zkVejXe0dpLmhl
- Modified file: openhands-sdk/openhands/sdk/conversation/impl/local_conversation.py
The fix is cleaner than PR #2466 because it addresses the actual bug in the run loop rather than working around it at resume time. Would you like me to commit the changes and create a PR?nutritious-balloon-65098
03/17/2026, 1:13 PMopenhands-sdk/openhands/sdk/conversation/impl/local_conversation.py at lines 602-606, removing STUCK from the pause check inside the while loop. This was based on my analysis that there was a redundant STUCK check that could cause the session to break immediately after the STUCK→RUNNING reset.
### Test Results
- All 112 tests in tests/sdk/conversation/local/ passed
- All 9 tests in test_agent_status_transition.py passed
- Pre-commit hooks passed
### Outcome
The user tested the fix but it did not resolve their issue - the conversation still becomes stuck after many successful steps.
### Next Steps
I asked the user to provide debug information from their stuck session to help diagnose the real root cause, including:
- The execution_status value
- Stuck detection configuration
- Last events before getting stuck
- Any error logs
- Agent configuration details
The investigation is ongoing pending this debug information.nutritious-balloon-65098
03/17/2026, 1:16 PMlocal_conversation.py where the run() method had conflicting logic:
1. Lines 586-592 (outside the while loop): Correctly resets STUCK → RUNNING when starting
2. Lines 602-606 (inside the while loop): Incorrectly checked for STUCK and broke immediately, causing the status to never actually transition to RUNNING
### Fix Applied
I made a minimal change to remove STUCK from the pause check inside the while loop:
diff
- if self._state.execution_status in [
- ConversationExecutionStatus.PAUSED,
- ConversationExecutionStatus.STUCK,
- ]:
+ if (
+ self._state.execution_status
+ == ConversationExecutionStatus.PAUSED
+ ):
### Current Status
- Tests pass (112 tests in conversation/local)
- Pre-commit passes
- However, the user reported the fix didn't work - they still got stuck sessions
### Additional Issue Identified
After the user's feedback, I realized there's likely a second issue: after the run loop exits, the status is never reset from STUCK. If the agent completes or the loop breaks for any reason, STUCK persists because there's no cleanup code.
### What I Need From the User
To debug further, I asked for:
1. The last event files (event-00700 and event-00701)
2. Any stuck/loop detection logs
3. Whether the agent was actually in a loop or working normally
This will help determine if it's a false-positive stuck detection, or if there's another code path causing the issue.nutritious-balloon-65098
03/17/2026, 1:20 PMnutritious-balloon-65098
03/17/2026, 1:26 PMnutritious-balloon-65098
03/17/2026, 1:29 PMlocal_conversation.py that caused sessions to get permanently stuck:
### Bug 1: Infinite stuck loop (CRITICAL)
- Location: Lines 640-645
- Problem: After stuck detection, the code used continue which went back to the top of the loop. On the next iteration, is_stuck() returned TRUE again (no new events!), creating an infinite loop that never exited.
- Fix: Changed continue to break so the run loop exits cleanly when stuck is detected.
### Bug 2: Resume recovery blocked
- Location: Lines 602-606
- Problem: Outside the loop, STUCK → RUNNING was correctly reset. But inside the loop, another check immediately broke if status was STUCK, preventing recovery.
- Fix: Removed STUCK from the pause check inside the loop.
### Verification
- All 112 tests in tests/sdk/conversation/local/ pass ✓
- All 9 status transition tests pass ✓
- Pre-commit hooks pass ✓
---
Would you like me to commit the changes and create a PR? The fix is cleaner and more targeted than PR #2466 - it fixes the actual bugs in the run loop rather than working around them at resume time.nutritious-balloon-65098
03/17/2026, 1:39 PMnutritious-balloon-65098
03/17/2026, 2:41 PMcontinue which went back to the top of the loop and triggered stuck detection again (same events), creating an infinite loop
2. Resume recovery blocked: Inside the run loop, there was a check for STUCK status that would immediately break, preventing recovery even though STUCK→RUNNING was reset outside the loop
3. False positive on resume: When sending a new message after getting stuck, the stuck detector would immediately trigger again because the old "stuck pattern" was still in the event history
### Fixes Applied (in openhands-sdk/openhands/sdk/conversation/impl/local_conversation.py)
1. Removed STUCK from pause check inside the while loop
2. Changed continue to break after stuck detection to exit the loop cleanly
3. Added first_iteration flag to skip stuck detection on first iteration, giving the agent a chance to process new user messages
4. Added event count tracking to only check for stuck patterns when new events have been added
### Verification
- All 112 tests in tests/sdk/conversation/local/ pass
- Pre-commit hooks pass
The fixes allow conversations to recover from stuck states when new user messages are sent, without requiring manual deletion of base_state.json.magnificent-tiger-32598
03/18/2026, 1:27 PMmagnificent-tiger-32598
03/18/2026, 5:43 PMchilly-france-44439
03/20/2026, 4:56 PMmagnificent-tiger-32598
03/20/2026, 4:57 PM