Preconditions:
Issue details:
Summary
Metals asks, via window/showMessageRequest, whether to import a workspace it has not seen before. Serena registers no handler for that request, so it comes back as MethodNotFound, Metals logs Unexpected error initializing server and imports nothing. The project then has no build server and no build target, and every cross-file query is answered by the fallback presentation compiler, which sees one file at a time — so find_referencing_symbols returns nothing, with no error at Serena's level to say why.
This is not a monorepo edge case. It is any Scala project that has not already been imported by something else. The Scala setup guide's Quick Start ("open your project in VS Code, accept Import build…") is a workaround for it, and simply doesn't work for many workflows (multiple independent worktrees, devcontainers).
Setup
- Serena
main @ 9a9d07e83d8c1cba3458992707f440c624446c6d
- Metals 1.6.4 (Serena's bundled default), Scala 3.3.6, sbt 1.11.7 (pinned by the fixture)
- OpenJDK 25.0.3, Python 3.14.6, Debian 13 (aarch64)
- No MCP client involved — driven directly through
SolidLanguageServer
- No configuration adjustments
Reproduction
Save as sscce.py at the root of a Serena checkout, then (uv sync --all-extras first if needed):
uv run python sscce.py /tmp/plain
Needs java, sbt and cs on PATH. It writes a perfectly ordinary single-module sbt project — no .bloop, no .bsp, nothing pre-imported — and asks for the references to Lib.greet, retrying for three minutes. Note that on a working Serena this causes Metals to run sbt bloopInstall and fetch Scala 3.3.6, so run it somewhere that is fine.
"""Serena + Metals on a single-root sbt project that has never been imported."""
import os
import shutil
import sys
import time
from solidlsp.language_servers.scala_language_server import ScalaLanguageServer
from solidlsp.ls_config import LanguageServerConfig, LanguageServerId
from solidlsp.settings import SolidLSPSettings
REPO = os.path.abspath(sys.argv[1])
# --- fixture: an ordinary sbt project at the repository root, no .bloop/.bsp ------------
shutil.rmtree(REPO, ignore_errors=True)
files = {
"build.sbt": 'ThisBuild / scalaVersion := "3.3.6"\n\nlazy val plain = (project in file("."))\n',
"project/build.properties": "sbt.version=1.11.7\n",
"src/main/scala/plain/Lib.scala": 'package plain\n\nobject Lib {\n def greet(who: String): String = s"hello $who"\n}\n',
"src/main/scala/plain/App.scala": 'package plain\n\nobject App {\n def main(args: Array[String]): Unit = println(Lib.greet("world"))\n}\n',
}
for rel, content in files.items():
path = os.path.join(REPO, rel)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(content)
ls = ScalaLanguageServer(LanguageServerConfig(ls_id=LanguageServerId.SCALA), REPO, SolidLSPSettings())
with ls.start_server_context():
refs = []
deadline = time.time() + 180
while time.time() < deadline:
# Lib.scala line 3 (0-based) is ` def greet(...)`; column 6 is on `greet`.
refs = ls.request_references(os.path.join("src", "main", "scala", "plain", "Lib.scala"), 3, 6)
if refs:
break
time.sleep(10)
print("references to Lib.greet:", [r["relativePath"] for r in refs])
Expected
references to Lib.greet: ['src/main/scala/plain/App.scala']
Actual
references to Lib.greet: []
/tmp/plain/.metals/metals.log:
INFO Started: Metals version 1.6.4 in folders '/tmp/plain' for client Serena .
ERROR Unexpected error initializing server:
org.eclipse.lsp4j.jsonrpc.ResponseErrorException: method 'window/showMessageRequest' not handled on client.
at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.handleResponse(RemoteEndpoint.java:220)
at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.consume(RemoteEndpoint.java:204)
…
INFO no build target found for /tmp/plain/src/main/scala/plain/Lib.scala. Using presentation compiler with project's scala-library version: 3.3.6
(Stack trace trimmed.) That last line then repeats for every attempt, for the full three minutes. There is no build server: no Connected to Build server, no .bloop/ produced.
The question Metals was asking is Messages.ImportBuild: "New sbt workspace detected, would you like to import the build?", offering Import build / Not now / Don't show again.
Analysis
Serena answers only the server-to-client requests a language server has registered a handler for; anything else is failed back as MethodNotFound (src/solidlsp/ls_process.py:433-442). ScalaLanguageServer._start_server registers none, so Metals' prompt is one of them. There is precedent for handling it elsewhere in the codebase — ansible_language_server.py:308 registers exactly this handler, added in #1170, for exactly this reason ("without this handler the client replies with MethodNotFound, which the ansible LS treats as fatal").
Declining the question rather than answering it would not help. There is a switch for it — disableShowMessageRequest, read from the metals.disable-show-message-request system property (MetalsServerConfig.scala:147-150, binaryOption at :193) — and since Serena launches the Metals JVM it could set it, though not over LSP, as it is not a client capability. But where it is set, ConfiguredLanguageClient.showMessageRequest (:52-64) answers with the prompt's own default, and for this prompt that is Not now (BloopInstall.scala:190-205): no import either. Answering is the only route from a fresh checkout to a build server.
Nor is there a Serena-side setting that helps: the workaround is to import the build with another tool first, which is what the setup guide's Quick Start describes. Once .bloop/ exists Metals auto-connects and never asks, which is presumably why this has gone unreported — the documented workflow steps around it.
(Metals references are at scalameta/metals @ 987b0cdfa11905abeee575de0968293f9837936e, under metals/src/main/scala/scala/meta/internal/: metals/Messages.scala:207-233 for the prompt, builds/BloopInstall.scala:174-213 for the request and how the answer is compared against ImportBuild.yes, metals/clients/language/ConfiguredLanguageClient.scala:52-64 and metals/MetalsServerConfig.scala:147-150 for the fallback.)
Related
Fix
PR incoming. Registers the handler on the Scala server and answer the three prompts that lead to a build server — Import build, Import changes, Connect — dismissing anything else with null.
With it, the script above prints the expected line, and the log shows time: ran 'sbt bloopInstall' in 5.54s followed by Connected to Build server: Bloop v2.0.17.
Drafted with the help of Claude Code. I reproduced the bug myself, verified the source citations and the log output, and edited the text; questions are mine to answer.
Preconditions:
Issue details:
Summary
Metals asks, via
window/showMessageRequest, whether to import a workspace it has not seen before. Serena registers no handler for that request, so it comes back asMethodNotFound, Metals logsUnexpected error initializing serverand imports nothing. The project then has no build server and no build target, and every cross-file query is answered by the fallback presentation compiler, which sees one file at a time — sofind_referencing_symbolsreturns nothing, with no error at Serena's level to say why.This is not a monorepo edge case. It is any Scala project that has not already been imported by something else. The Scala setup guide's Quick Start ("open your project in VS Code, accept Import build…") is a workaround for it, and simply doesn't work for many workflows (multiple independent worktrees, devcontainers).
Setup
main@9a9d07e83d8c1cba3458992707f440c624446c6dSolidLanguageServerReproduction
Save as
sscce.pyat the root of a Serena checkout, then (uv sync --all-extrasfirst if needed):Needs
java,sbtandcsonPATH. It writes a perfectly ordinary single-module sbt project — no.bloop, no.bsp, nothing pre-imported — and asks for the references toLib.greet, retrying for three minutes. Note that on a working Serena this causes Metals to runsbt bloopInstalland fetch Scala 3.3.6, so run it somewhere that is fine.Expected
Actual
/tmp/plain/.metals/metals.log:(Stack trace trimmed.) That last line then repeats for every attempt, for the full three minutes. There is no build server: no
Connected to Build server, no.bloop/produced.The question Metals was asking is
Messages.ImportBuild: "New sbt workspace detected, would you like to import the build?", offeringImport build/Not now/Don't show again.Analysis
Serena answers only the server-to-client requests a language server has registered a handler for; anything else is failed back as
MethodNotFound(src/solidlsp/ls_process.py:433-442).ScalaLanguageServer._start_serverregisters none, so Metals' prompt is one of them. There is precedent for handling it elsewhere in the codebase —ansible_language_server.py:308registers exactly this handler, added in #1170, for exactly this reason ("without this handler the client replies withMethodNotFound, which the ansible LS treats as fatal").Declining the question rather than answering it would not help. There is a switch for it —
disableShowMessageRequest, read from themetals.disable-show-message-requestsystem property (MetalsServerConfig.scala:147-150,binaryOptionat:193) — and since Serena launches the Metals JVM it could set it, though not over LSP, as it is not a client capability. But where it is set,ConfiguredLanguageClient.showMessageRequest(:52-64) answers with the prompt's own default, and for this prompt that isNot now(BloopInstall.scala:190-205): no import either. Answering is the only route from a fresh checkout to a build server.Nor is there a Serena-side setting that helps: the workaround is to import the build with another tool first, which is what the setup guide's Quick Start describes. Once
.bloop/exists Metals auto-connects and never asks, which is presumably why this has gone unreported — the documented workflow steps around it.(Metals references are at
scalameta/metals@987b0cdfa11905abeee575de0968293f9837936e, undermetals/src/main/scala/scala/meta/internal/:metals/Messages.scala:207-233for the prompt,builds/BloopInstall.scala:174-213for the request and how the answer is compared againstImportBuild.yes,metals/clients/language/ConfiguredLanguageClient.scala:52-64andmetals/MetalsServerConfig.scala:147-150for the fallback.)Related
find_referencing_symbolsoperation #688 — different bug (that reporter had runbloopInstallby hand), but the thread's "the fact that this special compilation is needed makes scala support very annoying" is about this friction. With the prompt answered, the special compilation is no longer the user's job.showMessageRequesthandler of its own precisely to work around this, and could drop it once this is fixed.Fix
PR incoming. Registers the handler on the Scala server and answer the three prompts that lead to a build server —
Import build,Import changes,Connect— dismissing anything else withnull.With it, the script above prints the expected line, and the log shows
time: ran 'sbt bloopInstall' in 5.54sfollowed byConnected to Build server: Bloop v2.0.17.Drafted with the help of Claude Code. I reproduced the bug myself, verified the source citations and the log output, and edited the text; questions are mine to answer.