LSP plugin: workspaceFolder defaults to null, breaking JDTLS project detection

Resolved 💬 2 comments Opened Mar 22, 2026 by vlzware Closed Apr 20, 2026

Summary

The official jdtls-lsp plugin (and likely other LSP plugins) doesn't set workspaceFolder in its config. Claude Code appears to send a null or empty rootUri in the LSP initialize request, causing JDTLS to fall back to "invisible project" / syntax-only mode. Every other LSP client (VSCode, Neovim, Emacs, etc.) defaults rootUri to the workspace/project root directory.

This makes JDTLS unable to:

  • Find .project / .classpath files (Eclipse project detection)
  • Find pom.xml / build.gradle (Maven/Gradle project detection)
  • Index the workspace for cross-file navigation

Steps to Reproduce

  1. Install jdtls-lsp@claude-plugins-official and have jdtls binary in PATH
  2. Open a Java project that has a .project file at the root
  3. Use any LSP operation (e.g., findReferences, goToDefinition)
  4. Observe: JDTLS log shows "Creating the Java project jdt.ls-java-project" (the fallback invisible project) instead of importing the actual project
  5. Observe: diagnostics show "X.java is a non-project file, only syntax errors are reported"

Root Cause

The jdtls-lsp plugin config in the official marketplace only specifies:

{
  "jdtls": {
    "command": "jdtls",
    "extensionToLanguage": { ".java": "java" },
    "startupTimeout": 120000
  }
}

No workspaceFolder is set. Claude Code does not appear to default it to the current working directory.

JDTLS logs confirm:

  • "Importers: GradleProjectImporter, MavenProjectImporter, EclipseProjectImporter, InvisibleProjectImporter"
  • "Workspace initialized in 22ms" (too fast — nothing was found)
  • Falls straight through to InvisibleProjectImporter

Secondary Issue: settings not delivered via workspace/didChangeConfiguration

The LSP plugin schema supports a settings field described as "Settings passed via workspace/didChangeConfiguration". However, even when set in .lsp.json:

{
  "jdtls": {
    "settings": {
      "java.project.sourcePaths": ["src"],
      "java.project.referencedLibraries": ["lib/*.jar"]
    }
  }
}

...JDTLS does not receive these settings. The invisible project's .classpath remains at defaults (path="src") rather than reflecting the configured source paths. This suggests workspace/didChangeConfiguration is never sent.

Workaround

Create a local plugin with workspaceFolder explicitly set, plus Eclipse project files (.project, .classpath) at the workspace root:

{
  "jdtls": {
    "command": "jdtls",
    "extensionToLanguage": { ".java": "java" },
    "workspaceFolder": "/absolute/path/to/project",
    "startupTimeout": 120000
  }
}

Load with claude --plugin-dir ./path/to/local/plugin after disabling the official plugin.

Expected Behavior

  • When workspaceFolder is not set in the plugin config, Claude Code should default it to the current working directory (consistent with all other LSP clients)
  • settings from the plugin config should be delivered to the LSP server via workspace/didChangeConfiguration after initialization

Environment

  • Claude Code: latest (2026-03-22)
  • JDTLS: 1.57.0-SNAPSHOT (milestone build Feb 2026)
  • OS: Linux (Ubuntu)
  • Java: OpenJDK 21

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗