Problem
The built-in kotlin-ls (JetBrains Kotlin LSP) fails to initialize within the configured timeout on large Android/Gradle projects. The LSP requires a full Gradle project sync before responding to the initialize request, which takes 2-5 minutes on projects with many dependencies.
Environment
- opencode v1.15.4
- Linux x86_64 (Nobara 43 / Fedora-based)
- Android project: AGP 8.11.0, ~760 source files, 50+ Gradle dependencies
- JDK 21 available
Observed Behavior
lsp_status shows kotlin-ls: installed; source=builtin
- Any
lsp_diagnostics call on .kt files returns: LSP request timeout (method: initialize)
- stderr shows macOS-specific
--add-opens warnings (harmless on Linux but indicates cross-platform script issues)
- Even with
"timeout": 300000 (5 minutes) in project config, initialization still times out
Attempted Workarounds (all failed)
-
Project config command override — Setting "command": ["kotlin-language-server"] in .opencode/opencode.json under lsp.kotlin-ls does NOT override the built-in binary. The JetBrains version at ~/.cache/opencode/bin/kotlin-ls/kotlin-lsp.sh is always used.
-
Project config disabled: true — Setting "disabled": true on kotlin-ls does not prevent it from being used.
-
Custom LSP name — Adding a new LSP entry like "kotlin-community" with custom command and .kt/.kts extensions does not appear in lsp_status and is never activated.
-
Increased timeout — "timeout": 300000 in project config has no observable effect.
Working Workaround (hacky)
Replacing the installed script at ~/.cache/opencode/bin/kotlin-ls/kotlin-lsp.sh with a wrapper that calls the community kotlin-language-server binary:
#!/bin/bash
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk
exec /path/to/kotlin-language-server "$@"
After pre-warming the Gradle cache (./gradlew dependencies), the community version initializes within the timeout and provides diagnostics successfully.
Root Causes
-
No user override path: The built-in LSP command cannot be overridden via project or global config. The source=builtin installation takes absolute precedence.
-
JetBrains LSP requires Gradle sync: Unlike the community kotlin-language-server (which can start incrementally), the JetBrains version blocks on full project model resolution before responding to initialize.
-
Timeout config may not propagate: The timeout field in project config appears to have no effect on the actual LSP initialization timeout.
Suggested Fixes (any of these would help)
-
Allow command override in user/project config — If a user specifies lsp.kotlin-ls.command, use that instead of the built-in binary.
-
Support disabled: true — Allow users to disable built-in LSP servers that do not work in their environment.
-
Increase default timeout for kotlin-ls — The JetBrains version legitimately needs 2-5 minutes on large projects. Consider a longer default or async initialization.
-
Offer community kotlin-language-server as alternative — The fwcd/kotlin-language-server initializes much faster and provides sufficient diagnostics for most use cases.
-
Pre-warm Gradle on first LSP start — Run ./gradlew dependencies in background before attempting LSP initialization.
Additional Context
- The JetBrains kotlin-lsp.sh script contains macOS-specific
--add-opens flags that produce warnings on Linux (cosmetic issue)
- The script bundles its own JRE 21, ignoring user-configured
JAVA_HOME
- Community kotlin-language-server v1.3.13 works correctly as a drop-in replacement after Gradle cache warm-up
- opencode was started from
/ (root directory), not the project directory — project-level .opencode/opencode.json config was not loaded, which may explain why config overrides had no effect. However, even when the config IS loaded, the builtin binary still takes precedence based on source=builtin behavior.
Problem
The built-in
kotlin-ls(JetBrains Kotlin LSP) fails to initialize within the configured timeout on large Android/Gradle projects. The LSP requires a full Gradle project sync before responding to theinitializerequest, which takes 2-5 minutes on projects with many dependencies.Environment
Observed Behavior
lsp_statusshowskotlin-ls: installed; source=builtinlsp_diagnosticscall on.ktfiles returns:LSP request timeout (method: initialize)--add-openswarnings (harmless on Linux but indicates cross-platform script issues)"timeout": 300000(5 minutes) in project config, initialization still times outAttempted Workarounds (all failed)
Project config
commandoverride — Setting"command": ["kotlin-language-server"]in.opencode/opencode.jsonunderlsp.kotlin-lsdoes NOT override the built-in binary. The JetBrains version at~/.cache/opencode/bin/kotlin-ls/kotlin-lsp.shis always used.Project config
disabled: true— Setting"disabled": trueonkotlin-lsdoes not prevent it from being used.Custom LSP name — Adding a new LSP entry like
"kotlin-community"with custom command and.kt/.ktsextensions does not appear inlsp_statusand is never activated.Increased timeout —
"timeout": 300000in project config has no observable effect.Working Workaround (hacky)
Replacing the installed script at
~/.cache/opencode/bin/kotlin-ls/kotlin-lsp.shwith a wrapper that calls the communitykotlin-language-serverbinary:After pre-warming the Gradle cache (
./gradlew dependencies), the community version initializes within the timeout and provides diagnostics successfully.Root Causes
No user override path: The built-in LSP
commandcannot be overridden via project or global config. Thesource=builtininstallation takes absolute precedence.JetBrains LSP requires Gradle sync: Unlike the community
kotlin-language-server(which can start incrementally), the JetBrains version blocks on full project model resolution before responding toinitialize.Timeout config may not propagate: The
timeoutfield in project config appears to have no effect on the actual LSP initialization timeout.Suggested Fixes (any of these would help)
Allow
commandoverride in user/project config — If a user specifieslsp.kotlin-ls.command, use that instead of the built-in binary.Support
disabled: true— Allow users to disable built-in LSP servers that do not work in their environment.Increase default timeout for kotlin-ls — The JetBrains version legitimately needs 2-5 minutes on large projects. Consider a longer default or async initialization.
Offer community kotlin-language-server as alternative — The fwcd/kotlin-language-server initializes much faster and provides sufficient diagnostics for most use cases.
Pre-warm Gradle on first LSP start — Run
./gradlew dependenciesin background before attempting LSP initialization.Additional Context
--add-opensflags that produce warnings on Linux (cosmetic issue)JAVA_HOME/(root directory), not the project directory — project-level.opencode/opencode.jsonconfig was not loaded, which may explain why config overrides had no effect. However, even when the config IS loaded, the builtin binary still takes precedence based onsource=builtinbehavior.