Summary
The diagnostics wait timeouts in packages/opencode/src/lsp/client.ts are hardcoded at 5s (document) and 10s (full). For language servers that need longer to parse a translation unit, the client always gives up first and returns no diagnostics — which is indistinguishable from "the file is clean".
This is a correctness problem rather than a performance one: an agent consuming the LSP cannot tell "no problems found" from "we stopped waiting", so it reports false confidence or stops trusting the tool.
// packages/opencode/src/lsp/client.ts:14-15
const DIAGNOSTICS_DOCUMENT_WAIT_TIMEOUT_MS = 5_000
const DIAGNOSTICS_FULL_WAIT_TIMEOUT_MS = 10_000
Environment
- opencode 1.18.4 (also reproduced against
dev @ 284214c)
- clangd 21.1.8, Linux x64
- Unreal Engine 5 game project, 23,382-entry
compile_commands.json
Reproduction
Any C++ file in a large Unreal project. One translation unit pulls in ~3,764 transitive headers, and clangd needs roughly 20s to parse it — measured directly over stdio LSP, independent of opencode:
| query |
time |
| first open of a UE file (cold) |
19–25s |
| same file again, still open |
0.00s |
| a sibling file in the same module |
19.03s |
Against opencode:
$ opencode debug lsp diagnostics /path/to/HGGameUserSettings.cpp
{
"/path/to/.clangd": []
}
The requested file is absent from the result entirely, after ~11s — consistent with 5s + 10s. The same file checked with the real compiler (clang++ -fsyntax-only, using the flags from compile_commands.json) compiles cleanly, and a deliberately broken variant reports its error correctly, so clangd and the configuration are both fine.
Not caused by configuration
Ruled out by measurement:
- Compile database staleness — 442 of 452 files present; clangd interpolates flags for the rest and returns correct symbols.
- Database size — scoping it 8.5× (23,382 → 2,741 entries) moved parse time only 27.1s → 24.5s.
.clangd force-include — removing it gives 14.2s → 10.5s and reintroduces 82 false errors. Still at the threshold.
--pch-storage=memory — no change (13.9s).
There is no configuration option to extend the wait.
Related
Suggested fix
Make the two waits configurable per LSP server, defaulting to the current constants so nothing changes for anyone who doesn't opt in:
With that applied locally, the same command returns the real diagnostic in 13s:
Error [3:13] Use of undeclared identifier 'this_symbol_does_not_exist'
I have a working patch (~35 lines across 5 files) and am happy to open a PR against this issue.
Summary
The diagnostics wait timeouts in
packages/opencode/src/lsp/client.tsare hardcoded at 5s (document) and 10s (full). For language servers that need longer to parse a translation unit, the client always gives up first and returns no diagnostics — which is indistinguishable from "the file is clean".This is a correctness problem rather than a performance one: an agent consuming the LSP cannot tell "no problems found" from "we stopped waiting", so it reports false confidence or stops trusting the tool.
Environment
dev@ 284214c)compile_commands.jsonReproduction
Any C++ file in a large Unreal project. One translation unit pulls in ~3,764 transitive headers, and clangd needs roughly 20s to parse it — measured directly over stdio LSP, independent of opencode:
Against opencode:
The requested file is absent from the result entirely, after ~11s — consistent with 5s + 10s. The same file checked with the real compiler (
clang++ -fsyntax-only, using the flags fromcompile_commands.json) compiles cleanly, and a deliberately broken variant reports its error correctly, so clangd and the configuration are both fine.Not caused by configuration
Ruled out by measurement:
.clangdforce-include — removing it gives 14.2s → 10.5s and reintroduces 82 false errors. Still at the threshold.--pch-storage=memory— no change (13.9s).There is no configuration option to extend the wait.
Related
Suggested fix
Make the two waits configurable per LSP server, defaulting to the current constants so nothing changes for anyone who doesn't opt in:
With that applied locally, the same command returns the real diagnostic in 13s:
I have a working patch (~35 lines across 5 files) and am happy to open a PR against this issue.