oraios/serena · error · SolidLSPException

JDTLS requires JDK {JDTLS_MIN_JDK_VERSION}+ but '{java_exe}'

Error message

JDTLS requires JDK {JDTLS_MIN_JDK_VERSION}+ but '{java_exe}' is JDK {major_version} (located via {source}, java.home={real_jdk_home}). Install a newer JDK and update ls_specific_settings.java.java_home or JAVA_HOME.

What it means

SolidLSPException thrown by _resolve_system_jdk when the located Java executable reports a major version below JDTLS_MIN_JDK_VERSION (17). The library interrogates the JVM directly via -XshowSettings:properties and refuses to start JDTLS on an unsupported JDK, reporting where the java came from and its real java.home.

Source

Thrown at src/solidlsp/language_servers/eclipse_jdtls.py:618

                    log.warning(f"JAVA_HOME='{env_home}' invalid (no '{candidate}'), falling back to PATH.")

            if java_exe is None:
                java_in_path = shutil.which("java")
                if java_in_path is None:
                    raise SolidLSPException(
                        "Could not locate a Java installation for JDTLS. "
                        "Set ls_specific_settings.java.java_home, set JAVA_HOME environment variable, "
                        f"or ensure 'java' is on PATH. Required: JDK {JDTLS_MIN_JDK_VERSION}+."
                    )
                java_exe = java_in_path
                source = f"PATH ({java_in_path})"

            # interrogate the JVM for its real java.home and version (single source of truth)
            real_jdk_home, major_version = EclipseJDTLS.DependencyProvider._inspect_java(java_exe)

            # validate version
            if major_version < JDTLS_MIN_JDK_VERSION:
                raise SolidLSPException(
                    f"JDTLS requires JDK {JDTLS_MIN_JDK_VERSION}+ but '{java_exe}' is JDK {major_version} "
                    f"(located via {source}, java.home={real_jdk_home}). "
                    f"Install a newer JDK and update ls_specific_settings.java.java_home or JAVA_HOME."
                )
            log.info(f"Resolved JDK {major_version} via {source}; java.home={real_jdk_home}; java_exe={java_exe}.")

            # prefer to use bin/java from the *real* JDK home (so JDTLS subprocesses that read JAVA_HOME
            # find a consistent layout); only fall back to the original locator if the real-home variant
            # is missing for some reason.
            real_java = str(Path(real_jdk_home) / "bin" / java_exe_name)
            if os.path.exists(real_java):
                java_exe = real_java

            return real_jdk_home, java_exe

        @staticmethod
        def _inspect_java(java_exe: str) -> tuple[str, int]:
            """

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Install JDK 17+ and point ls_specific_settings.java.java_home (or JAVA_HOME) at it
  2. Check the current version: <java_exe> -version, and upgrade if below 17
  3. Remove a stale JAVA_HOME entry that shadows the newer JDK
  4. Update PATH so a modern JDK's bin directory comes first

Example fix

// before
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk
// after
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
Defensive patterns

Strategy: validation

Validate before calling

import subprocess, re
def jdk_major(java_exe: str) -> int | None:
    out = subprocess.run([java_exe, "-version"], capture_output=True, text=True)
    m = re.search(r'version "(\d+)', out.stderr + out.stdout)
    return int(m.group(1)) if m else None

assert (jdk_major(java_exe) or 0) >= 17, "JDTLS needs JDK 17+"

Type guard

def is_jdk17_plus(java_exe: str) -> bool:
    major = jdk_major(java_exe)
    return major is not None and major >= 17

Try / catch

try:
    ls = start_jdtls()
except SolidLSPException as e:
    if "requires JDK" in str(e):
        os.environ["JAVA_HOME"] = "/usr/lib/jvm/java-21"  # switch to modern JDK
        ls = start_jdtls()
    else:
        raise

Prevention

When it happens

Trigger: _resolve_system_jdk finds a java executable (via java_home setting, JAVA_HOME, or PATH) but _inspect_java returns major_version < 17; raised from _setup_from_existing_install.

Common situations: System default java is JDK 8/11; JAVA_HOME points at an old JDK used by a legacy build; a wrapper script shadows a newer JDK; macOS /usr/bin/java stub resolving to an outdated JVM.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/5144aef7f111c1a9. Report an issue: GitHub.