oraios/serena · error · FileNotFoundError
ls_specific_settings.java.runtimes entry
Error message
ls_specific_settings.java.runtimes entry '{entry['name']}' points to a path that does not exist: {path}. Fix: update the path in ~/.serena/serena_config.yml (ls_specific_settings -> java -> runtimes), or remove the entry. What it means
Serena validates each Java runtime entry configured under ls_specific_settings.java.runtimes in ~/.serena/serena_config.yml during JDTLS initialization. If the entry's 'path' does not exist on disk, _resolve_configured_runtimes raises FileNotFoundError so the language server fails fast instead of later breaking code resolution. It names the offending entry and tells you which config key to fix.
Solutions
- Open ~/.serena/serena_config.yml, find ls_specific_settings -> java -> runtimes, and update the entry's path to an existing JDK home
- Or remove the stale entry from the runtimes list so Serena falls back to runtime discovery
- Verify with: ls <path>/bin/java (the path must point to a JDK home, not the java binary)
- If using SDKMAN/Homebrew, re-link or reinstall the JDK at the expected location
Example fix
# before (serena_config.yml)
runtimes:
- name: "17"
path: /usr/lib/jvm/jdk-17.0.2 # removed by system upgrade
// after
runtimes:
- name: "17"
path: /usr/lib/jvm/jdk-17.0.9 # existing JDK home
Defensive patterns
Strategy: validation
Validate before calling
import os, yaml
cfg = yaml.safe_load(open(os.path.expanduser('~/.serena/serena_config.yml')))
for rt in (cfg.get('ls_specific_settings', {}).get('java', {}).get('runtimes') or []):
if not os.path.isdir(rt.get('path', '')):
print(f"invalid runtime path for {rt.get('name')}: {rt.get('path')}") Type guard
def runtime_entry_ok(entry: dict) -> bool:
import os
return isinstance(entry.get('path'), str) and os.path.isdir(entry['path']) Try / catch
try:
server = LanguageServer.create(LanguageServerId.JAVA, ...)
except FileNotFoundError as e:
logger.error("Fix java runtimes in ~/.serena/serena_config.yml: %s", e)
# fall back or abort with a clear user message Prevention
- After any JDK upgrade/uninstall, re-check serena_config.yml runtimes paths
- Use a JDK discovery helper (SDKMAN/Homebrew paths) to generate entries
- Add serena_config.yml path checks to environment bootstrap scripts
- Keep runtimes entries minimal; rely on auto-discovery when possible
When it happens
Trigger: Calling _create_base_initialize_params (i.e., starting the Eclipse JDTLS language server) while a runtimes entry in ~/.serena/serena_config.yml has a 'path' that os.path.exists() cannot find — a deleted/renamed JDK directory, a typo, or a stale entry left after a JDK upgrade.
Common situations: Upgrading or uninstalling a JDK (e.g., removing a Homebrew/SDKMAN-managed JDK) leaving the old path in serena_config.yml; moving a JDK between machines; typos in the configured path; container/CI images where the configured JDK was never installed.
Related errors
- Both 'jdtls_path' and 'lombok_path' must be set together in…
- Config directory ' ' not found. This JDTLS distribution…
- Gradle user home directory not found
- Invalid jdtls_path ' ': 'plugins/' directory not…
- Provided jdtls_path ' ' is not an existing directory. Fix…
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/846198e51db771e8.
Report an issue: GitHub.
Appendix: source
Thrown at src/solidlsp/language_servers/eclipse_jdtls.py:887
f"got {type(configured_runtimes).__name__}: {configured_runtimes!r}"
)
# validate each entry and normalize it to the shape JDT-LS expects...
validated_runtimes: list[dict[str, Any]] = []
for entry in configured_runtimes:
if not isinstance(entry, dict) or "name" not in entry or "path" not in entry:
raise ValueError(
f"Invalid ls_specific_settings.java.runtimes entry {entry!r}: each entry requires at least a 'name' and a 'path' key."
)
path = entry["path"]
if not os.path.exists(path):
error_msg = (
f"ls_specific_settings.java.runtimes entry '{entry['name']}' points to a path that "
f"does not exist: {path}. Fix: update the path in ~/.serena/serena_config.yml "
f"(ls_specific_settings -> java -> runtimes), or remove the entry."
)
log.error(error_msg)
raise FileNotFoundError(error_msg)
runtime: dict[str, Any] = {"name": entry["name"], "path": path}
if "default" in entry:
runtime["default"] = bool(entry["default"])
for optional_key in ("sources", "javadoc"):
if optional_key in entry:
runtime[optional_key] = entry[optional_key]
validated_runtimes.append(runtime)
log.info(f"Registering additional JDT-LS runtime '{runtime['name']}' from custom settings: {path}")
return validated_runtimes
def _create_base_initialize_params(self) -> dict:
"""
Returns the initialize parameters for the EclipseJDTLS server.
"""
# Look into https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/preferences/Preferences.java to understand all the options available
View on GitHub (pinned to 7fcbca7e62)