oraios/serena · error · SolidLSPException
Invalid jdtls_path '{jdtls_path}': 'plugins/' directory not
Error message
Invalid jdtls_path '{jdtls_path}': 'plugins/' directory not found.
Expected upstream JDTLS layout (plugins/, config_<platform>/, features/) at the root. If you pointed at a vscode-java extension, use '<extension>/server' instead. What it means
This SolidLSPException is raised when jdtls_path exists but lacks a 'plugins/' subdirectory, meaning it does not match the upstream JDTLS layout (plugins/, config_<platform>/, features/). A very common cause is pointing jdtls_path at the vscode-java extension root instead of its 'server' subdirectory.
Source
Thrown at src/solidlsp/language_servers/eclipse_jdtls.py:483
and the system-installed JDK. No downloads are performed.
:param jdtls_path: absolute path to the JDTLS root (containing ``plugins/`` and ``config_<platform>/``)
:param lombok_path: absolute path to the Lombok jar (mandatory; agent is always attached)
:param custom_settings: language-server-specific settings from ls_specific_settings.java
:return: populated RuntimeDependencyPaths with ``gradle_path`` set to ``None``
"""
# validate jdtls_path structure (root + plugins dir)
jdtls_root = Path(jdtls_path)
if not jdtls_root.is_dir():
raise SolidLSPException(
f"Provided jdtls_path '{jdtls_path}' is not an existing directory.\n"
f"Fix: extract jdt-language-server-*.tar.gz from "
f"https://download.eclipse.org/jdtls/snapshots/ or run 'brew install jdtls', "
f"then set ls_specific_settings.java.jdtls_path to the extracted directory."
)
plugins_dir = jdtls_root / "plugins"
if not plugins_dir.is_dir():
raise SolidLSPException(
f"Invalid jdtls_path '{jdtls_path}': 'plugins/' directory not found.\n"
f"Expected upstream JDTLS layout (plugins/, config_<platform>/, features/) at the root. "
f"If you pointed at a vscode-java extension, use '<extension>/server' instead."
)
# resolve the main equinox launcher jar (excluding platform-specific native fragments)
launcher_jar = EclipseJDTLS.DependencyProvider._resolve_launcher_jar(plugins_dir)
# resolve the platform-specific config directory under jdtls_root
config_dir = EclipseJDTLS.DependencyProvider._resolve_config_dir(jdtls_root)
# validate lombok jar exists
if not Path(lombok_path).is_file():
raise SolidLSPException(
f"Provided lombok_path '{lombok_path}' does not exist or is not a file.\n"
f"Fix: download lombok jar from https://projectlombok.org/downloads/ or use the one "
f"from your local Maven cache (~/.m2/repository/org/projectlombok/lombok/<version>/lombok-<version>.jar)."
)View on GitHub (pinned to 7fcbca7e62)
Solutions
- If pointing at a vscode-java extension, append '/server' to the path (e.g. '<ext_dir>/server').
- Inspect jdtls_path for a nested directory containing plugins/, config_<platform>/, features/ and point at that root.
- Re-extract the official JDTLS tarball so the layout sits directly under jdtls_path.
- On macOS with brew, use the libexec directory of the jdtls formula as jdtls_path.
Example fix
// before "jdtls_path": "/Users/me/.vscode/extensions/redhat.java-1.30.0" // after "jdtls_path": "/Users/me/.vscode/extensions/redhat.java-1.30.0/server"
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
root = Path(jdtls_path).expanduser()
if root.is_dir() and not (root / 'plugins').is_dir():
server = root / 'server' # vscode-java extension layout
if (server / 'plugins').is_dir():
settings['ls_specific_settings']['java']['jdtls_path'] = str(server) Type guard
def has_upstream_jdtls_layout(path: str) -> bool:
from pathlib import Path
root = Path(path).expanduser()
return root.is_dir() and (root / 'plugins').is_dir() and (root / 'features').is_dir() Try / catch
try:
ls = SolidLSP(java_config)
except SolidLSPException as e:
if "'plugins/' directory not found" in str(e):
cfg = java_config['ls_specific_settings']['java']
cfg['jdtls_path'] = str(Path(cfg['jdtls_path']) / 'server')
ls = SolidLSP(java_config)
else:
raise Prevention
- Check for plugins/, config_<platform>/, features/ at the configured root before saving settings.
- For vscode-java extensions, always use the '<extension>/server' subdirectory.
- Avoid symlink/nested-extraction surprises: extract tarballs with 'tar -xzf' directly into the target root.
When it happens
Trigger: _setup_from_existing_install passes is_dir() for jdtls_root but (jdtls_root / 'plugins').is_dir() is False during EclipseJDTLS startup in upstream mode.
Common situations: User set jdtls_path to a vscode-java VSIX extension directory (needs '<extension>/server'); extracted the tarball into a nested folder so the real root is one level deeper; pointed at a brew Cellar parent rather than the libexec directory.
Related errors
- Both 'jdtls_path' and 'lombok_path' must be set together in
- Resource paths inside the vscode-java {vscode_java_version}
- Provided jdtls_path '{jdtls_path}' is not an existing direct
- Provided lombok_path '{lombok_path}' does not exist or is no
- Config directory '{config_dir}' not found. This JDTLS distri
AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29).
Data as JSON: /api/errors/62a38dc950766b67.
Report an issue: GitHub.