Skip to content

Kotlin hover tests flaky: KLS NullPointerException when Gradle classpath resolution fails in CI #134

@LakshyAAAgrawal

Description

@LakshyAAAgrawal

Problem

The Kotlin Language Server (KLS v1.3.13) intermittently throws a NullPointerException on textDocument/hover requests when it cannot resolve the project classpath via Gradle or Maven. This causes test_multilspy_kotlin_hover and test_multilspy_kotlin_sync_hover to fail non-deterministically in CI.

Failing tests:

Both tests are currently marked xfail(strict=False) in #133.

Root cause

On GitHub Actions runners, /usr/bin/gradle and /usr/bin/mvn exist but cannot be executed by the KLS Java process (error=13, Permission denied), even after sudo chmod a+x. The chmod fixes shell access but not JVM ProcessBuilder access — likely a runner security policy issue.

When classpath resolution fails, the KLS falls back to kotlinc stdlib only. With incomplete type information, hover requests on certain symbols trigger a NullPointerException inside the KLS:

Internal error: java.lang.NullPointerException
java.util.concurrent.CompletionException: java.lang.NullPointerException
    at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(Unknown Source)
    at java.base/java.util.concurrent.CompletableFuture.completeThrowable(Unknown Source)
    at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(Unknown Source)

This surfaces as multilspy.lsp_protocol_handler.server.Error: Internal error. (-32603).

Evidence that it's flaky (not consistent)

From CI run #24214120325:

  • Python 3.10: all Kotlin tests passed (both async and sync hover)
  • Python 3.14: all Kotlin tests passed
  • Python 3.12: async hover passed, sync hover failed

Same Gradle permission errors on all three, but the NullPointerException only triggers non-deterministically.

Possible fixes

  1. Upstream KLS fix: The KLS should handle missing classpath gracefully on hover instead of throwing NPE. This is a bug in fwcd/kotlin-language-server.
  2. Use a test repo that doesn't need Gradle: The current test repo is the KLS source itself (a Gradle project). A simpler Kotlin project with no build system dependency would avoid the classpath issue entirely.
  3. Runner-level fix: Figure out why JVM ProcessBuilder can't exec /usr/bin/gradle after chmod a+x on GitHub runners.

Metadata

Metadata

Assignees

No one assigned

    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