You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
codemode: execute hangs until eviction when a program awaits a promise nothing can settle #54340
A Code Mode execute program that awaits a promise nothing can settle never finishes. The interpreter has no timers, so a promise settles only through a tool or extension call, or through the program's own code. Once neither is running, nothing can ever settle it. execute has no time limit either, so the session holds its turn indefinitely. After 60 minutes the location's inactivity eviction (#51343) interrupts the step, and the session goes idle as "Step interrupted". The model never learns what went wrong.
An agent hit this by trying to use execute to poll a review status between checks, with await new Promise(r => r) as a "sleep". The step hung from 15:01:42 to 16:01:59 UTC and ended on the same second that location services evicted was logged for its directory.
Plugins
Local plugins only (session messaging and session PR badges). Not involved.
OpenCode version
v2 dev build 202610080821. The code path is unchanged on current v2.
Steps to reproduce
Ask the agent to run this with execute: await new Promise(r => r); return 1
The tool call stays running and never returns.
After 60 minutes the step ends as "Step interrupted".
Thanks for the clear report. I reproduced this with opencode-drive and the simulated model:
The model calls execute with return 1. It returns at once (control).
The model then calls execute with await new Promise(r => r)\nreturn 1.
About 95 s later the execute row is still spinning, with no timeout or diagnostic. The only way out is interrupting the step.
This happens on @opencode/cli 2.0.26 (your dev build isn't published, so I used the latest release) and still on the latest dev (7b3d4ce), run from source. The screenshots below show the step still running on each. Exporting a video failed on my side, so no recording is attached. The script below reproduces it.
In the code, createCodeMode passes no limits, so the interpreter's timeout never applies. The interpreter also doesn't notice that nothing is left that could settle the awaited promise.
Related: #54220 (no timeout for execute or plugin tool calls in general), PR #54299 (a shared tool timeout), and #51343 (the 60-minute inactivity eviction that eventually ends the step).
Reproduction script (drive.ts)
// Repro for #54340: a Code Mode `execute` program that awaits a promise nothing// can settle never finishes; there is no deadline or "deadlock" diagnostic.import{Effect}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"constWAIT_SECONDS=Number(process.env.WAIT_SECONDS??90)exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true},},({ llm, ui })=>Effect.gen(function*(){// Control: a program that settles normally returns at once.yield*llm.queue(Llm.toolCall({index: 0,id: "call_ok",name: "execute",input: {code: "return 1"}}),Llm.finish("tool-calls"),)yield*llm.queue(Llm.text("Control execute returned."))yield*ui.submit("Run return 1 with execute")yield*ui.waitFor("Control execute returned.")yield*ui.screenshot("control-done")// The report: awaiting a promise whose resolver is never called.yield*llm.queue(Llm.toolCall({index: 0,id: "call_hang",name: "execute",input: {code: "await new Promise(r => r)\nreturn 1"},}),Llm.finish("tool-calls"),)yield*ui.submit("Now run the never-settling promise with execute")yield*Effect.sleep("5 seconds")yield*ui.screenshot("hang-t5")yield*Effect.sleep(`${WAIT_SECONDS} seconds`)yield*ui.screenshot(`hang-t${WAIT_SECONDS+5}`)constframe: any=yield*ui.capture()yield*Effect.log("\n"+frame.lines.map((l: any)=>l.spans.map((s: any)=>s.text).join("")).join("\n"),)// Only way out is interrupting the whole step.yield*ui.press("escape")yield*ui.press("escape")yield*Effect.sleep("3 seconds")yield*ui.screenshot("after-interrupt")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
fix(codemode): fail a program that stalls instead of holding the turn
opencode-agent commentedon Oct 10, 2026
Thanks for the clear report. I reproduced this with opencode-drive and the simulated model:
executewithreturn 1. It returns at once (control).executewithawait new Promise(r => r)\nreturn 1.executerow is still spinning, with no timeout or diagnostic. The only way out is interrupting the step.This happens on @opencode/cli 2.0.26 (your dev build isn't published, so I used the latest release) and still on the latest
dev(7b3d4ce), run from source. The screenshots below show the step still running on each. Exporting a video failed on my side, so no recording is attached. The script below reproduces it.In the code,
createCodeModepasses no limits, so the interpreter's timeout never applies. The interpreter also doesn't notice that nothing is left that could settle the awaited promise.Related: #54220 (no timeout for
executeor plugin tool calls in general), PR #54299 (a shared tool timeout), and #51343 (the 60-minute inactivity eviction that eventually ends the step).Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.