Repository navigation
Description
Description
In @opencode/codemode, concurrent async functions lose updates to shared variables, and a caller can continue before an async function's body reaches its first await.
The interpreter runs each async call, promise reaction and generator body on its own Effect fiber, and Effect yields a fiber after 2,048 operations. When several program fibers are ready at once (for example after the tool calls in a Promise.all return), their statements interleave mid-expression: total = total + 1 reads total, another fiber runs and writes it, and the first fiber's write drops those updates. JavaScript runs one job at a time, so both programs below are deterministic natively.
We hit this with programs that fold tool results from Promise.all into shared counters and strings: rows were dropped without any error.
Present on v2 at 55dde88 and in @opencode/[email protected].
Plugins
None
OpenCode version
@opencode/[email protected] (v2 at 55dde88)
Steps to reproduce
- In an empty directory:
echo '{"type":"module"}' > package.json && npm i @opencode/[email protected] [email protected] - Save as
repro.mjs:
import { CodeMode } from "@opencode/codemode"
import { Effect } from "effect"
const programs = {
// Two async functions add to a shared counter after an await.
counter: `
let total = 0
const work = async () => {
await null
for (let i = 0; i < 1000; i++) total = total + 1
}
await Promise.all([work(), work()])
return total
`,
// An async function's body runs synchronously up to its first await.
prefix: `
let count = 0
const work = async () => {
for (let i = 0; i < 1000; i++) count = count + 1
await null
}
work()
return count
`,
}
const AsyncFunction = (async () => {}).constructor
for (const [name, code] of Object.entries(programs)) {
const node = await new AsyncFunction(code)()
const result = await Effect.runPromise(CodeMode.execute({ tools: {}, code }))
console.log(`${name}: node ${node}, codemode ${result.value}`)
}node repro.mjs(Bun prints the same)
Expected:
counter: node 2000, codemode 2000
prefix: node 1000, codemode 1000
Actual (every run):
counter: node 2000, codemode 1853
prefix: node 1000, codemode 145
Screenshot and/or share link
No response
Operating System
Ubuntu 24.04 (Linux 6.8); Node 24.21.0, Bun 1.4.2
Terminal
No response
Sent from my Claude
Activity
opencode-agent commentedon Oct 10, 2026
Thanks for the clear repro. I can confirm this.
I ran your script against
@opencode/[email protected], and also from source on the latestv2(55dde88). Both gave the same numbers every run:So two things happen:
await.The script below reproduces both. I've passed this on to the maintainers.
Reproduction script (repro.mjs)
Run it:
bun repro.mjsrekram1-node commentedon Oct 20, 2026
oh hello there mr rhys