Skip to content

kotlin-ls: JetBrains LSP initialization timeout on large Android projects; user command override ineffective #28289

Description

@simuxipalacheshi

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

  1. lsp_status shows kotlin-ls: installed; source=builtin
  2. Any lsp_diagnostics call on .kt files returns: LSP request timeout (method: initialize)
  3. stderr shows macOS-specific --add-opens warnings (harmless on Linux but indicates cross-platform script issues)
  4. Even with "timeout": 300000 (5 minutes) in project config, initialization still times out

Attempted Workarounds (all failed)

  1. 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.

  2. Project config disabled: true — Setting "disabled": true on kotlin-ls does not prevent it from being used.

  3. 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.

  4. 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

  1. No user override path: The built-in LSP command cannot be overridden via project or global config. The source=builtin installation takes absolute precedence.

  2. 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.

  3. 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)

  1. Allow command override in user/project config — If a user specifies lsp.kotlin-ls.command, use that instead of the built-in binary.

  2. Support disabled: true — Allow users to disable built-in LSP servers that do not work in their environment.

  3. Increase default timeout for kotlin-ls — The JetBrains version legitimately needs 2-5 minutes on large projects. Consider a longer default or async initialization.

  4. Offer community kotlin-language-server as alternative — The fwcd/kotlin-language-server initializes much faster and provides sufficient diagnostics for most use cases.

  5. 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.

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions