Skip to content

fix: server-generated message IDs to prevent client/server clock skew#11869

Open
KONFeature wants to merge 2 commits intoanomalyco:devfrom
KONFeature:fix/correct-web-message-id
Open

fix: server-generated message IDs to prevent client/server clock skew#11869
KONFeature wants to merge 2 commits intoanomalyco:devfrom
KONFeature:fix/correct-web-message-id

Conversation

@KONFeature
Copy link
Copy Markdown

What does this PR do?

How did you verify your code works?

  • Local testing with separate backend (bun run serve) and app dev server (bun dev)
  • Artificially skewed the Web UI's timestamp generation to produce IDs that sort incorrectly relative to server IDs. Confirmed the optimistic message gets reconciled to the correct server ID without duplicates or misplacement
  • Delayed server response to observe the optimistic message persisting, then verified it swaps cleanly when the message.updated event arrives

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 3, 2026

The following comment was made by an LLM, it may be inaccurate:

No duplicate PRs found

@KONFeature KONFeature force-pushed the fix/correct-web-message-id branch from 24bac52 to e24ca10 Compare February 3, 2026 08:38
@KONFeature
Copy link
Copy Markdown
Author

ready to be reviewed / merged @adamdotdevin if you got some time to look at it 🙏
It would fix quite a blocking issue on our end (we got some firecracker vm with opencode + vscode, and right now the opencode web part is just not usable because of this

@charles-brooks
Copy link
Copy Markdown

This matches a hang I’m seeing that I believe is caused by client/server clock skew + optimistic client-generated message IDs.

Repro (web UI):

  1. Run opencode serve on a host where the system clock is not reliably NTP-synced (or otherwise skewed vs the client).
  2. Connect from another machine (I’m using Tailscale + remote server).
  3. Send a prompt that triggers a permission-gated tool call (e.g. glob/read on an external directory).
  4. Observe: session sits on “Considering next steps” indefinitely because the permission prompt never renders, while the backend is blocked on a pending permission.asked.

In my case, the message ordering was inverted (assistant sorted before user) because the client optimistic messageID was ahead of server time, so the UI couldn’t associate the
permission request to the tool part.

A local UI workaround (associate assistant messages by parentID instead of list position) fixes it, but your approach (server-generated IDs + clientMessageID reconciliation) looks like
the correct root fix.

@sjawhar
Copy link
Copy Markdown

sjawhar commented Mar 12, 2026

We've been investigating the same root cause and took a tactical approach (fixing consumers to use array position instead of ID ordering for fork/revert/prompt-wrapping). While that eliminates the symptoms, this PR's approach of making the server authoritative for message IDs eliminates the bug class entirely. The clientMessageID field for optimistic reconciliation is the right pattern. Would love to see this merged — it's the complete solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web UI: client-generated message IDs cause infinite processing loop when client/server clocks diverge

3 participants