Description
Under certain conditions, opencode sessions fail to terminate correctly, causing the assistant to continuously create new messages in an infinite loop, even when the model has returned a finish=stop status.
Plugins
No response
OpenCode version
1.2.1
Steps to reproduce
Bug Report: Session Loop Termination Condition Fails Causing Infinite Loop
Summary
Under certain conditions, opencode sessions fail to terminate correctly, causing the assistant to continuously create new messages in an infinite loop, even when the model has returned a finish=stop status.
Environment
- opencode version: 1.2.1
- Model: glm-5
- OS: Linux
- Session ID: ses_3a477417effeooCd5Cq2mJV3lE
Problem Description
After executing a security analysis task, the model returned finish=stop multiple times, but the system did not correctly terminate the loop. Instead, it continued creating new assistant messages, eventually producing 96 messages until the user manually aborted.
Key Metrics
| Metric |
Value |
| User messages |
2 |
| Assistant messages |
94 |
| Assistant message finish values |
88 with stop, 6 with tool-calls |
| Final state |
MessageAbortedError (user manual abort) |
| Accumulated input tokens |
44,000+ |
Root Cause Analysis
The issue is in the loop termination condition at lines 263-271 of packages/opencode/src/session/prompt.ts:
if (
lastAssistant?.finish &&
!["tool-calls", "unknown"].includes(lastAssistant.finish) &&
lastUser.id < lastAssistant.id
) {
log.info("exiting loop", { sessionID })
break
}
The Problem
The condition lastUser.id < lastAssistant.id uses string comparison to determine message ordering.
Actual message IDs:
- User message:
msg_e6f0bd865e63
- Assistant message:
msg_c5b88be94001tLa8xeuxsiub6h
String comparison:
msg_e... vs msg_c...
- Second character:
e (ASCII 101) vs c (ASCII 99)
- Result:
"e" > "c" → lastUser.id < lastAssistant.id = false
Loop Flow
while (true) {
1. Get message stream
2. lastUser = first user message (msg_e6f0bd865e63)
3. lastAssistant = last assistant message (finish=stop)
4. Check termination: lastUser.id < lastAssistant.id → false
5. Condition not met, continue loop
6. Create new assistant message
7. Model returns finish=stop
8. Back to step 1... (infinite loop)
}
Steps to Reproduce
- Start opencode serve
- Send a complex task that triggers multiple tool calls (e.g., using a skill for security analysis)
- After task completion, model returns
finish=stop
- Observe whether the session terminates correctly
Expected Behavior
When the model returns finish=stop, the session should correctly terminate the loop and stop creating new assistant messages.
Actual Behavior
The session continues creating new assistant messages in an infinite loop until:
- User manually aborts
- Or another error is triggered
Impact
- Resource consumption: CPU, memory, and API calls continuously grow
- Cost increase: Unnecessary model API calls
- User experience: Session hangs and cannot end normally
Suggested Fixes
Option 1: Remove ID Comparison (Recommended)
Since the finish status already indicates the model has completed:
if (
lastAssistant?.finish &&
!["tool-calls", "unknown"].includes(lastAssistant.finish)
) {
log.info("exiting loop", { sessionID })
break
}
Option 2: Use Timestamp Comparison
if (
lastAssistant?.finish &&
!["tool-calls", "unknown"].includes(lastAssistant.finish) &&
lastUser.time.created < lastAssistant.time.created
) {
log.info("exiting loop", { sessionID })
break
}
Option 3: Ensure IDs are Comparable
If ID comparison is necessary, ensure the ID generation strategy produces lexicographically correct identifiers (e.g., using timestamp prefixes).
Relevant Logs
INFO session.prompt step=0 sessionID=ses_3a477417effeooCd5Cq2mJV3lE loop
INFO session.prompt step=1 sessionID=ses_3a477417effeooCd5Cq2mJV3lE loop
...
INFO session.prompt step=88 sessionID=ses_3a477417effeooCd5Cq2mJV3lE loop
// "exiting loop" log never appears
Database Verification
-- Verify message IDs and finish status
SELECT id, json_extract(data, '$.role'), json_extract(data, '$.finish')
FROM message
WHERE session_id='ses_3a477417effeooCd5Cq2mJV3lE'
ORDER BY time_created;
-- Results show:
-- User message ID: msg_e6f0bd865e63 (finish: null)
-- Assistant message ID: msg_c5b88be94001tLa8xeuxsiub6h (finish: stop)
-- String comparison: "e" > "c", causing the condition to always be false
Related Files
packages/opencode/src/session/prompt.ts - Loop termination logic
packages/opencode/src/session/processor.ts - Finish status setting
packages/opencode/src/id/id.ts - ID generation strategy
Report Date: 2026-02-14
Reporter: opencode user fsdgGFF
Screenshot and/or share link
No response
Operating System
linux
Terminal
No response
Description
Under certain conditions, opencode sessions fail to terminate correctly, causing the assistant to continuously create new messages in an infinite loop, even when the model has returned a
finish=stopstatus.Plugins
No response
OpenCode version
1.2.1
Steps to reproduce
Bug Report: Session Loop Termination Condition Fails Causing Infinite Loop
Summary
Under certain conditions, opencode sessions fail to terminate correctly, causing the assistant to continuously create new messages in an infinite loop, even when the model has returned a
finish=stopstatus.Environment
Problem Description
After executing a security analysis task, the model returned
finish=stopmultiple times, but the system did not correctly terminate the loop. Instead, it continued creating new assistant messages, eventually producing 96 messages until the user manually aborted.Key Metrics
stop, 6 withtool-callsRoot Cause Analysis
The issue is in the loop termination condition at lines 263-271 of
packages/opencode/src/session/prompt.ts:The Problem
The condition
lastUser.id < lastAssistant.iduses string comparison to determine message ordering.Actual message IDs:
msg_e6f0bd865e63msg_c5b88be94001tLa8xeuxsiub6hString comparison:
msg_e...vsmsg_c...e(ASCII 101) vsc(ASCII 99)"e" > "c"→lastUser.id < lastAssistant.id= falseLoop Flow
Steps to Reproduce
finish=stopExpected Behavior
When the model returns
finish=stop, the session should correctly terminate the loop and stop creating new assistant messages.Actual Behavior
The session continues creating new assistant messages in an infinite loop until:
Impact
Suggested Fixes
Option 1: Remove ID Comparison (Recommended)
Since the
finishstatus already indicates the model has completed:Option 2: Use Timestamp Comparison
Option 3: Ensure IDs are Comparable
If ID comparison is necessary, ensure the ID generation strategy produces lexicographically correct identifiers (e.g., using timestamp prefixes).
Relevant Logs
Database Verification
Related Files
packages/opencode/src/session/prompt.ts- Loop termination logicpackages/opencode/src/session/processor.ts- Finish status settingpackages/opencode/src/id/id.ts- ID generation strategyReport Date: 2026-02-14
Reporter: opencode user fsdgGFF
Screenshot and/or share link
No response
Operating System
linux
Terminal
No response