Skip to content

Concurrent stdio instances on one project hand the same Eclipse JDTLS -data workspace to N language servers, causing unbounded CPU/RAM and silent index corruption #1944

Description

@stefan-pavlovic-ded

Checklist

  • read the relevant parts of the documentation and verified that the issue cannot be solved by adjusting configuration
  • understood that the Serena Dashboard can be disabled through the config
  • understood that, by default, a client session will start a separate instance of a Serena server
  • understood that, for multi-agent setups, the Streamable HTTP/SSE mode should be used
  • understood that non-project files are ignored using either .gitignore or the corresponding setting in .serena/project.yml
  • looked for similar issues and discussions, including closed ones (see below)
  • made sure it's an actual issue, not a question

Summary

When two stdio Serena instances activate the same project, both spawn an Eclipse JDT language server and hand each one the identical -data workspace directory. Eclipse JDT workspaces are single-writer by design, so the two servers continuously invalidate each other's index. The result is that neither ever reaches an idle state: they sat at 160% and 128% CPU with 1.4 GB + 2.6 GB RSS on a single Gradle/Java project, indefinitely, on an otherwise-healthy machine.

Nothing warns the user. There is no lock, no error surfaced through MCP, and no log line indicating the collision — it presents only as the machine becoming slow.

Relationship to existing issues

I found the prior art and want to be explicit about what is and isn't new:

The argument for treating this separately: stdio-per-session is the default, HTTP mode is opt-in, and the failure mode here is silent index corruption plus a multi-GB / multi-core resource leak. A user following the defaults gets no signal that anything is wrong.

Environment

  • Serena 1.2.0 (uv tool), --context=copilot-cli --project-from-cwd
  • language_backend: LSP
  • Ubuntu 24.04.4 LTS, 12-core i7-1365U
  • Project: Java/Gradle (build.gradle, settings.gradle), moderate size
  • MCP client: GitHub Copilot app — each session spawns its own stdio Serena instance

Reproduction

  1. With language_backend: LSP, open two concurrent MCP sessions whose cwd is the same Java project.
  2. Each activates the project and starts an Eclipse JDT language server.
  3. Inspect the -data argument of both JDTLS processes.

Both receive the same path:

$ tr '\0' '\n' < /proc/625237/cmdline | grep -A1 -x -- -data | tail -1
/home/sp/.serena/language_servers/static/EclipseJDTLS/workspaces/2269b098e07d8bdba1bd239a2fac6177/data_dir

$ tr '\0' '\n' < /proc/626656/cmdline | grep -A1 -x -- -data | tail -1
/home/sp/.serena/language_servers/static/EclipseJDTLS/workspaces/2269b098e07d8bdba1bd239a2fac6177/data_dir

The workspace hash is derived from the project path, so every concurrent session on a given project collides on one workspace directory.

Neither settles. Sampled ~5 minutes after start, with the project otherwise idle:

pid=625237   160.0% CPU   1428 MB
pid=626656   128.2% CPU   2579 MB

Secondary observation: repeated StackOverflowError in the shared workspace

The same workspace's Eclipse log contains 149 StackOverflowError occurrences across 10 rotated .bak_N.log files (Eclipse rotates on restart, so the workspace has been re-initialised at least 10 times). The stack is regex recursion:

java.lang.StackOverflowError
	at java.base/java.util.regex.Pattern$Branch.match(Unknown Source)
	at java.base/java.util.regex.Pattern$GroupHead.match(Unknown Source)
	at java.base/java.util.regex.Pattern$LazyLoop.match(Unknown Source)
	at java.base/java.util.regex.Pattern$GroupTail.match(Unknown Source)
	at java.base/java.util.regex.Pattern$BranchConn.match(Unknown Source)
	at java.base/java.util.regex.Pattern$CharProperty.match(Unknown Source)

This looks like catastrophic backtracking on some input file rather than a concurrency symptom, so it may well be a separate bug — I'm including it because it shares the workspace and may compound the restart churn. Happy to split it into its own issue if you'd prefer.

Suggested fixes

Roughly in order of how well they'd contain the failure:

  1. Namespace the JDTLS -data directory per language-server instance, not solely per project path — e.g. append a PID/session/instance suffix. This makes concurrent sessions safe by construction, at the cost of some disk and duplicate indexing.
  2. Reuse a single language server per project across instances (in-process reference counting), which avoids the duplicate indexing cost entirely and is the semantically ideal fix.
  3. At minimum, detect and warn. Take an advisory lock on the workspace directory; if it's already held, log loudly and surface an MCP-visible warning rather than proceeding into silent corruption. Even just a startup log line naming the workspace path would make this diagnosable — I only found it by inspecting /proc/<pid>/cmdline.

Option 3 alone would have turned this from "my machine is mysteriously slow" into a one-line diagnosis.

Workaround for others hitting this

Either switch to the documented single persistent server (HTTP/SSE) mode, or avoid concurrent MCP sessions rooted in the same project. To recover after it has happened, stop the orphaned servers and delete the corrupted workspace so it rebuilds:

rm -rf ~/.serena/language_servers/static/EclipseJDTLS/workspaces/<hash>

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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