Repository navigation
Description
Summary
opencode run intermittently hangs before creating a session. When it happens the process stays alive but produces zero stdout, emits no error, and never progresses past message=init in the log. The only way out is an external timeout.
The failure is intermittent, not deterministic. Over 61 invocations in one day I measured a 44% success rate (27/61), with hourly rates swinging between 8% and 77%. A later controlled 40-run trial in a "good" window produced 40/40 successes, so the failure window and the healthy window can be minutes apart with no configuration change in between.
Read-only subcommands (--version, agent list, models) always respond instantly, even while run is hanging.
Environment
| opencode | 1.18.4 (also reproduced on 1.17.11) |
| Install | npm install -g opencode-ai (nvm-managed prefix, no sudo) |
| OS | macOS 26.5.2 (build 25F84), Darwin 25.5.0, arm64 |
| Hardware | Apple M4 Pro, 48 GB unified memory |
| Node | v24.17.0 (nvm) |
| npm | 12.0.0 |
| Provider | Ollama 0.32.3 via @ai-sdk/openai-compatible at http://127.0.0.1:11434/v1 |
Relevant config (~/.config/opencode/opencode.jsonc), though the issue reproduces with no user config at all:
{
"$schema": "https://opencode.ai/config.json",
"share": "disabled",
"autoupdate": true,
"model": "ollama/qwen3-coder:30b",
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (Local)",
"options": { "baseURL": "http://127.0.0.1:11434/v1", "timeout": 1800000 }
}
}
}Steps to reproduce
Reproduction is probabilistic. There is no known trigger; the same command succeeds or hangs depending on when it is run.
mkdir -p /tmp/oc-repro && cd /tmp/oc-repro
timeout 120 opencode run "answer in one word: what is 1+1?"
echo "exit=$?" # 0 when it works (~19s), 124 when it hangsRun this repeatedly with a gap between attempts. In failure windows it hangs on most attempts; in healthy windows it succeeds every time in ~19 seconds.
Do not judge by exit code alone. Because stdout is buffered until completion, a hung run and a slow run look identical from the shell. The reliable discriminator is whether a session was created:
grep -c 'message=created' ~/.local/share/opencode/log/opencode.logObserved behaviour
Log signature
A successful run progresses through:
init → created → event → loop → shell → init → booting → stream → loop → exiting loop → disposing instance
A hung run stops dead at the first init:
timestamp=... message="creating instance" directory=/tmp/oc-repro
timestamp=... message=fromDirectory directory=/tmp/oc-repro
timestamp=... message=bootstrapping directory=/tmp/oc-repro
timestamp=... message=loading path=/Users/<user>/.config/opencode/config.json
timestamp=... message=loading path=/Users/<user>/.config/opencode/opencode.json
timestamp=... message=loading path=/Users/<user>/.config/opencode/opencode.jsonc
timestamp=... message="all LSPs are disabled"
timestamp=... message="all formatters are disabled"
timestamp=... message=init
<nothing further — process stays alive until killed>
No created, no stream, no error, no warning at --log-level DEBUG.
Timing is bimodal, not a slowdown
Across 40 controlled runs, every successful run completed in 18–19 seconds (min 18, max 19). Hung runs never complete — observed up to 900s. There is no middle ground: a run either finishes in ~19s or does not progress at all.
Network evidence — connection to models.dev held open with no progress
During a hung run, lsof showed an ESTABLISHED connection to 172.67.69.147:443 held for the entire 30-second sampling window while the run made no progress:
$ lsof -nP -a -p <pid> -i
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
opencode. 14462 vinyl 15u IPv4 ... 0t0 TCP 192.168.x.x:50476->172.67.69.147:443 (ESTABLISHED)
172.67.69.147 resolves as one of the A records for models.dev:
$ dig +short models.dev
104.26.9.108
104.26.8.108
172.67.69.147
(registry.npmjs.org resolves to a different range, 104.16.x.x, so this is models.dev specifically.)
Meanwhile the host itself was perfectly reachable from the same machine at the same time:
$ curl -s -o /dev/null -w "namelookup=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} total=%{time_total}\n" https://models.dev/
namelookup=0.001497 connect=0.140799 tls=0.287761 total=1.107086 # HTTP 200
System resolver was also instant (socket.getaddrinfo("models.dev", 443) → 0.00s).
So the remote endpoint was healthy while opencode sat on an established connection to it without progressing.
A second, different hang shape
Not every hang looks the same. In other hung runs, lsof showed the process holding no sockets at all — not to models.dev, and not even to the local Ollama endpoint on 127.0.0.1:11434:
t=2 PID=14286 connections=[none]
t=4 PID=14286 connections=[none]
...
t=30 PID=14286 connections=[none]
This suggests there may be more than one stall path, or a stall that occurs before any socket is opened. I could not determine which.
OPENCODE_OFFLINE=1 does not suppress the models.dev request
In a controlled, interleaved 40-run trial (20 with OPENCODE_OFFLINE=1, 20 without, alternating, fixed 45s gap between runs), connections to models.dev were sampled during every run:
| Arm | Runs | Sessions created | models.dev connection observed |
|---|---|---|---|
OPENCODE_OFFLINE=1 |
20 | 20/20 | 4 |
| control | 20 | 20/20 | 4 |
Identical. The environment variable did not reduce contact with models.dev.
Note this sampling is a lower bound: connections were polled every 2s, so short-lived requests during fast (~19s) runs are frequently missed. A zero should be read as "not observed", not "did not happen". The signal that matters here is that both arms show the same rate.
Frequency data
Uncontrolled observations, 2026-07-24 — 61 opencode run invocations, classified by whether a session was created:
| Hour (UTC) | Sessions created / attempts |
|---|---|
| 01–09 | 10/13 (77%) |
| 10 | 4/9 (44%) |
| 11–12 | 1/13 (8%) |
| 13 | 0/4 (0%) |
| 14–15 | 12/22 (55%) |
| Total | 27/61 (44%) |
Controlled trial, 15:26–16:08 UTC — 40 runs, alternating arms, fixed 45s gap: 40/40 succeeded, all in 18–19s. This window began roughly 10 minutes after a stretch of 6 consecutive failures, with no configuration change in between.
What was ruled out
Every one of these was tested; the hang reproduced after each:
| Hypothesis | How it was ruled out |
|---|---|
| User config | Rolled back through three prior states, then removed opencode.jsonc entirely |
| Project-level config | Reproduced both with and without a project opencode.jsonc |
| Corrupted install | Clean reinstall to 1.18.4 with postinstall scripts explicitly allowed |
| Plugins | Reproduced with --pure |
| Local state / DB | Deleted opencode.db, -shm, -wal; recreated (56 tables) and still hangs |
| OS-level resource leak | Full machine restart |
| Binary integrity / Gatekeeper | Mach-O arm64, no com.apple.quarantine (only com.apple.provenance) |
| Ollama unhealthy | Direct /api/generate call answered in 1.7s while run was hanging |
| DNS / network path | getaddrinfo 0.00s; curl https://models.dev/ → HTTP 200 in 1.1s |
| Disk / memory | 69 GiB free, ~50% memory free |
| Auto-update in flight | --version instant; no update activity in logs |
One incidental finding while reinstalling: with npm's allowScripts policy active, npm install -g opencode-ai@latest completes but silently skips the postinstall script, leaving a broken install whose --version prints "reinstall opencode-ai without the --ignore-scripts flag". Given autoupdate: true is the default, a self-update under that policy could leave users in a broken state. This is separate from the hang (the hang persisted after a correct reinstall) but may be worth handling.
What I think is happening
Stated as a hypothesis, not a conclusion — I do not have enough evidence to confirm it:
opencode appears to contact models.dev during startup, and at least one code path can wait on that request indefinitely with no timeout and no error surfaced. The observed ESTABLISHED-but-idle connection is consistent with this. What I cannot explain is the second hang shape where no sockets exist at all.
If startup does depend on a network fetch, a bounded timeout with a fallback to cached data (and a log line on failure) would turn a silent indefinite hang into a recoverable, diagnosable condition.
What would help
- Is a
models.dev(or other remote) fetch on therunstartup path, and does it have a timeout? - Is there a supported way to make startup fully offline?
OPENCODE_OFFLINE=1did not appear to affect the request in my testing. - Would you accept a log line at the point where init blocks, so this failure is diagnosable without
lsof?
I have raw per-run data (timestamps, exit codes, elapsed, session-created flags, connection samples) for all 101 runs and can attach it if useful.
Activity
github-actions commentedon Jul 24, 2026
This issue might be a duplicate of existing issues. Please check:
models.devfetch (same ESTABLISHED-but-idle TCP connection pattern during init, same lack of timeout)models.devfetch lacks network resilience — no timeout, no backoff, causes startup stalls in restricted/flaky networksmodels.devis not responding (earlier instance of the same root cause)Your investigation (ESTABLISHED connection to
172.67.69.147=models.dev, no progress, no error, no timeout) points to the same underlying issue described in those reports. The intermittency you observed — healthy windows vs. failure windows — is consistent withmodels.devitself being slow or partially degraded rather than fully unreachable, which would explain whycurlsucceeds (fast path) while the opencode fetch stalls on a slower/different connection.The second hang shape (no sockets at all) may be a separate code path, so it could be worth noting as an addition to one of those existing issues rather than a duplicate.
JazielGuerrero commentedon Jul 30, 2026
I'm seeing this as well (
opencode runhangs). In my case it hangs 100% of the time. I'm running OpenCode inside a Daytona sandbox through their Go SDK.After debugging, I traced it to this line:
opencode/packages/opencode/src/cli/cmd/run.ts
Line 416 in ceb4890
Since the execution environment is not a TTY and its stdin behaves differently than expected, this line blocks indefinitely:
await Bun.stdin.text()A simple way to check if you're hitting the same issue is to run:
If stdin isn't blocking, you should immediately see:
In my environment, it hangs instead and never reaches that validation.
As a workaround, I pipe the prompt into stdin so EOF is delivered correctly. For example:
or
opencode run < prompt_file.txtzealchou commentedon Aug 4, 2026
Third independent confirmation, on a platform not yet represented here — and, more usefully, a deterministic reproduction. The report notes "Reproduction is probabilistic. There is no known trigger", so this may help whoever picks it up.
@JazielGuerrero's diagnosis (
await Bun.stdin.text()incli/cmd/run.ts) matches everything we observed. The missing piece is why it looks intermittent: it isn't. It is fully determined by whether the launching environment handsopencode runa stdin that ever reaches EOF.Deterministic repro
Measured on our machine: A hung 5/5, B succeeded 10/10.
This also explains the observations in the original report that looked mysterious:
spawnwith the defaultstdio: 'pipe'and no explicitstdin.end()does not.opencode run --attachagainst a healthyopencode serve: the server's/sessionlist showed no new session at all, because the client blocks before it sends anything.Environment
npm install -g opencode-ai@ai-sdk/openai-compatibleon127.0.0.1Different OS, different arch, different provider from the two cases already in this thread — the trigger is the same.
Workaround
Append
< /dev/nullto every non-interactiveopencode runinvocation. That took our batch pipeline from intermittent indefinite hangs to 6/6 first-try successes.Suggested fix
Only read stdin when there is a reason to. Two options that would both have avoided this for us:
Either way, a bounded read would turn "hangs forever with no output and no error" into a normal run.
emilaiev commentedon Aug 4, 2026
Fourth platform — and a second, distinct blocking resource: not stdin, but the TCP connect to
opencode.aiduring startup.Environment
npm install -g opencode-aiopencode-go(cloud) — model API confirmed healthy during freeze windows via direct callsSame symptom:
opencode runalive, zero model output, no session created, healthy windows minutes away from frozen ones with no config change.Deterministic A/B repro (run today on 1.18.13)
Stdin pinned to
/dev/nullin both arms, so @zealchou's variable is eliminated:The only difference between the arms is the packet drop.
Controls — what it is not
ENETUNREACHand Happy Eyeballs prefers IPv4. The hang is IPv4SYN-SENT./dev/nullboth times, and the blocked process had six open TCP connects — a process blocked inBun.stdin.text()would show none. @zealchou's stdin case is real (we adopted< /dev/nulleverywhere as hardening), but it cannot explain SYN-SENT sockets.Why it looks intermittent
opencode.aiis intermittently slow from a given network path, not down. Connect attempts sit in kernel SYN retransmit for minutes, which produces the minutes-wide good/bad windows the original report measured by hour.Suggested fix
Bound the startup sync to
opencode.ai: a connect timeout plus an overall budget (e.g. 5s / 15s), then continue degraded and create the session anyway. A silent remote should cost seconds, not the run. Together with @zealchou's bounded stdin read, the two fixes would cover every hang shape reported in this thread.Local mitigation meanwhile
A supervisor that kills a run producing zero output at 60s and re-dials after 90s (freeze windows are minutes-wide, so the retry usually lands in a healthy one) took our headless batch from silent indefinite hangs to 12/12 starts.
VinylStage commentedon Aug 5, 2026
Fourth independent confirmation, and I can now retract my own original diagnosis.
I filed this report. My investigation pointed at
models.dev(an ESTABLISHED-but-idle TCP connection during init), and the duplicate-detection bot above followed that lead. That was the wrong trail. @JazielGuerrero and @zealchou have the actual cause, and I reproduced their determinism test on a platform not yet in this thread.Repro on macOS / arm64
Same two arms as @zealchou, unchanged:
exit=124every time, 45s wall clock, 0 bytes on stdoutexit=0, 2–37s (first run slower — model load)Not probabilistic. Deterministic in both directions.
qwen3-coder:30b) over the OpenAI-compatible endpointWorth noting the version: @zealchou measured 1.18.10, I measured 1.18.5, on a different OS, different arch, and a different local-inference stack. Same trigger, so this is not recent and not platform-specific.
Why my original "intermittent, 8–77% by hour" numbers fit this
My report described a failure rate that swung wildly by time of day. Measured then:
I treated the swing as a property of the environment. Under the stdin explanation it is a property of how each batch was launched, and one observation I could never explain now falls out cleanly:
The thing that changed was not the config. It was that the 40 runs were driven by a purpose-built shell harness rather than the launcher used before it. Under @zealchou's explanation, that harness handed
opencode runa stdin that reached EOF, so every run completed.Caveat, stated plainly: I did not record the stdin state of each run at the time, so I cannot retroactively prove which launcher each of those 61 runs used. This is consistency with the hypothesis, not independent proof of it. The 5/5 vs 6/6 above is the proof; this section is just the anomaly that no longer needs a special explanation.
Workaround
< /dev/nullon every non-interactive invocation. Confirmed here.On the suggested fix
@zealchou's option 1 — skip the stdin read entirely when a prompt was already passed as an argument — would have prevented every failure I logged. In all 61 of my runs the prompt was supplied as an argument, so nothing was ever going to be merged in from stdin; the read was pure cost.
I would add one thing regardless of which option is chosen: the failure mode itself is worth fixing separately. No output, no error, no session, no log line past
message=init, and an exit only when something external kills it. That is what turned a one-line stdin bug into a multi-day investigation that produced a wrong root cause. A bounded read that loggedstdin: waiting for EOFeven once would have ended it in minutes.Happy to run further tests on macOS/arm64 if that helps.
postoso commentedon Aug 27, 2026
Still reproduces on 1.18.23 (brew tap, macOS): opencode run with an inherited open stdin hangs indefinitely at startup, timeout kills it with no output and no session created; the same invocation with < /dev/null succeeds immediately. The redirect remains a reliable workaround.
fix(scripts): give every llm_backends subprocess an already-EOF stdin
z80690 commentedon Aug 31, 2026
Same issue on Windows. OpenCode 1.18.25 (also reproduced on 1.18.23 and 1.18.16):
opencode run --pure --agent build -m opencode/mimo-v2.5-free "say OK"hangs at the firstinitin the log — ~62 seconds of zero output/error, no session created, then "cleanup prune=7.days" and the process stays alive until killed. Reproduced in both the project dir and a clean empty dir. TUI mode works fine; only headlessrunhangs. Also confirmed api.opencode.ai reachable (HTTP 200), 0 credentials in auth. This blocks all headless/CI usage. Happy to run any diagnostic you suggest.postoso commentedon Sep 1, 2026
The TUI-works / headless-run-hangs split you are seeing is the tell, and it matches what I traced on macOS.
opencode run reads stdin to EOF before it does anything else. The TUI path never does this, which is why only run hangs. If the process inherits an stdin that is open and never closes, which is the normal case for a CI runner, a background job, or an agent harness, it waits there forever. Nothing is logged past init because nothing has happened yet, and no session is created, so there is no session id to recover from afterwards.
The one-token check: add a stdin redirect and run the identical command.
opencode run --pure --agent build -m opencode/mimo-v2.5-free "say OK" < /dev/null
On 1.18.25 here that is the whole difference. Without the redirect: exit 124 under timeout, zero bytes on stdout, empty stderr. With it: clean run. I measured 5 of 5 hangs without and 5 of 5 successes with when I first chased this, and it still reproduces the same way on 1.18.25 today.
If that fixes it for you, then it is not intermittent and it is not network, it is just whether the calling shell happened to leave stdin open. That also explains why it looked flaky across environments rather than consistently broken.
Refresh the kit for Oct 2026: dead tags, watchlist, install docs, Lev…
Vijayapardhu commentedon Oct 21, 2026
Adding a deterministic cause for this one — it may not be intermittent after all.
Repro on Windows 11 / OpenCode 2.1.2: when the working directory is a git work-tree with a very large untracked file set,
opencode runhangs before creating a session, with zero stdout and no error — exactly the symptom described here.The discriminator appears to be the size of the untracked set, not a flaky window:
git ls-files --others --exclude-standard.gitignoreopencode runbeforeopencode runafterA child
git.exerunningstays resident at ~99% CPU (>207s CPU observed, still running after 5+ minutes) and holds
index.lockin the snapshot repo. No provider request is ever made, and nosession/session_v2row is written — which is consistent with "no session created" in this report.The working directory in my case was
$HOME(a git work-tree with no commits and no.gitignore), where the legacy Windows junctions re-exposeAppDataas nine extra trees and push the untracked set to ~1.13M paths.So one concrete way to test the 44%-success-rate theory: measure
git ls-files --others --exclude-standard | wc -lin the cwd of the failing and succeeding runs. If the failures correlate with a large untracked count, the trigger is the snapshot indexer, not a network or plugin window.Worth also noting that read-only subcommands (
opencode models,opencode debug config) returning instantly whilerunhangs is consistent with this — they never reach the snapshot indexer.Filed as #57841 with the full reproduction, since it covers the Windows-specific mechanics. Related: #48657.
opencodejr commentedon Oct 28, 2026
Thanks for the very thorough investigation and the timing and network data.
This report is about OpenCode v1 (1.18.4 / 1.17.11, the
opencode-ainpm package). v1 now only gets fixes for critical bugs such as data loss, security problems, or breakage with no workaround. An intermittent hang that a retry gets past is unlikely to be fixed there.We'd encourage you to try v2 (the
@opencode/clinpm package, which provides theopencodecommand). The startup code there is a separate implementation. Its models.dev catalog fetch stops after 10 seconds, can fall back to a cached catalog, and logsFailed to fetch models.devwhen it fails, rather than waiting forever on the connection. That matches the timeout, fallback and log line you suggested. We haven't confirmed that it fixes your exact case, though, especially the second hang shape where the process has no sockets open.If this also happens on v2, or you believe it is critical for v1, please reply here with the v2 version and a log from a hung run, and we'll take another look.
opencodejr commentedon Oct 29, 2026
Closing this as not planned. It's an intermittent
opencode runhang on OpenCode v1 (1.18.4 / 1.17.11), and v1 only gets fixes for critical bugs. Retrying gets past this hang, so it doesn't count as critical. We didn't hear back after the last comment.Thanks again for the detailed investigation. If you see the same hang on v2 (
@opencode/cli), please open a new issue with the v2 version and a log from a hung run, and link back to #38723.