**Problem**
The native thin client discards -J JVM options before it starts the
server, so sbt -J-Xmx2G starts the server with the runner's default
1 GB heap. sbt.bat does not handle -J on the command line: it passes
the option to sbt as a command, which exits with "Not a valid
command". Its default memory check also misses heap options given on
the command line or as -XX:MaxRAM and RAM percentages, so the
appended -Xmx1024m overrides them.
**Solution**
sbtn passes -J options to the server script, and strips -J when it
starts the launcher JAR through java. A -J split out of a quoted
command stays in that command, and a bare -J is dropped. sbt.bat
strips -J, adds the option to the JVM options, rejoins -J-D and -J-XX
values that cmd.exe splits at '=', and passes -J options on to sbtn.
Its default memory check ignores quotes and checks the same options
as the Unix runner.
Generated-by: OpenAI Codex
Generated-by: Claude Code
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
Problem: The Unix launcher ignores JAVA_HOME and selects Java from PATH when JAVACMD is absent.
Solution: Check JAVA_HOME/bin/java before falling back to PATH while preserving explicit --java-home and JAVACMD precedence.
Fixes#9794
This is essentially applying the same fix as in #8795 but for the Windows sbt.bat script.
We now only set -Dsbt.global.base when explicitly asked for with the --sbt-dir option.
**Problem**
1. On Windows, sbt.bat re-parses its own already-received arguments a second time internally, via call/goto with an unquoted variable splice (call :run !SBT_ARGS!, and similarly for -D/-XX flags, several _SBT_OPTS-sourced flags, and the native-client dispatch path). That extra re-tokenization could let &, |, (, or ) inside an argument escape their quoting and run as separate shell commands.
2. The -D/-XX/-- argument handling spliced the raw argument value into a for /F ... in ("%g%") do ( ... ) construct nested up to four levels deep inside multi-line if blocks. Apparently, that confuses cmd to miscount the parentheses.
**Solution**
1. Call :run without the argument.
2. Avoid for /F
Problem: -V is consumed by the launcher instead of sbt in sbt tasks -V.
Solution: in the parser's -V behavior, lookback to see if there are commands going before it, in which case, forward -V to sbt.
**Problem**
-java-home wasn't fully honored on Windows: sbtw rejected the single-dash form, silently ignored bad paths, and didn't propagate the JDK to the sbt/sbtn child; sbt.bat didn't fix up PATH/JAVACMD, and a project .java-version could override an explicit -java-home. Residual #963 gaps (the original javac-from-PATH bug was fixed long ago).
**Solution**
New SelectedJava seam in sbtw resolves the JDK once (--java-home > JAVACMD > JAVA_HOME > PATH) and applies one env overlay on every launch path; sbt.bat's handler now sets PATH/JAVACMD and a one-hop marker so .java-version defers to an explicit -java-home.
JDK_HOME > JAVA_HOME (the issue's "even more desired" ordering) is intentionally **not** implemented — it only mattered when JAVA_HOME pointed at a JRE without javac, and JDK 17+ (required by sbt 2.x) no longer ships standalone JREs, so JAVA_HOME always resolves to a full JDK.
sbt.bat fails to start in client/server mode on Windows, falling back to running the full JVM in the foreground.
sbtn uses CreateProcess to spawn the server process. The original %%20 path encoding doesn't work in batch delayed expansion context, and the default install path C:\Program Files (x86) contains spaces that CreateProcess splits at.
**Problem**
sbt runner script defaults to sbtn, even on the operating system
where sbtn is not available.
**Solution**
This fallbacks to the jvm client.
Problem
When build.properties contains whitespaces like sbt.version = 1.12.12, parsing fails and the detected sbt version falls back to 2.0.0.
Solution
Trim whitespaces in build.properties.
**Problem**
`dependencyTree` with `--browse` can throw when desktop browse is unavailable (for example on Wayland/headless environments), causing command failure.
**Solution**
Handle unsupported desktop/browse actions and runtime browse failures gracefully by logging a warning instead of throwing, and add regression tests for unsupported/throwing desktop scenarios.
Generated-by: Cursor Codex 5.3
**Problem**
sbt bspConfig writes the absolute path of the current Java binary into .bsp/sbt.json. When the user switches Java versions (via sdkman, cs java, etc.) or removes that JDK, the IDE fails to start the sbt BSP server because the hardcoded path is stale or gone.
**Solution**
When an sbt launcher script is available (via `sbt.script` system property or PATH lookup), generate:
"argv": ["/path/to/sbt", "bsp"]
**Problem**
When you pass -sbt-dir "/Users/a' dog" on the command line, the launcher correctly produces:
-Dsbt.global.base=/Users/a' dog
But when you put the same option into .sbtopts, the launcher previously split the line on spaces without respecting quotes, so the resulting -Dsbt.global.base was truncated (for example, -Dsbt.global.base=/Users/a'). This made .sbtopts behavior inconsistent with CLI behavior and broke setups where the global sbt directory path contains spaces and an embedded quote.
Avoid launching sbt just to render --version by reading sbt.version directly from project/build.properties in the shell script, batch script, and sbtw wrapper. Tighten launcher integration assertions to verify version output no longer depends on the sbtVersion command output.
**Problem**
Running sbt 2.x with JDK 8 produces a confusing "server was not
detected" error because the JDK version check only required JDK 8+
and only ran in the non-native-client path.
**Solution**
Move java_version detection before the native client decision and add
checkJava17ForSbt2 that requires JDK 17+ when sbt major version >= 2.
Fixes#8813
* [2.x] fix: Fail early when sbt 2.x is run with JDK < 17 (sbtw)
Move JDK version check before native client decision in sbtw and
require JDK 17+ when build.properties declares sbt 2.x.
* [2.x] fix: Fail early when sbt 2.x is run with JDK < 17 (sbt.bat)
Move checkjava before native client decision in sbt.bat and require
JDK 17+ when build.properties declares sbt 2.x.
* [2.x] test: Add minimumJdkVersion helper and unit tests for sbtw
Extract JDK version check logic into Runner.minimumJdkVersion for
testability. Add RunnerSpec with tests for sbt 1.x, 2.x, and 3.x
version detection.
* [2.x] test: Bump fake java to JDK 17 for integration tests
The fake java script used by launcher integration tests reported
JDK 8. Since sbt 2.x now requires JDK 17+, the citest2 (sbt 2.x)
integration tests would fail with the new JDK version check.
* Simulate JDK 9+ rt.jar handling in fake java script
Instead of silently ignoring --rt-ext-dir (which causes sbt.bat
to mkdir on an empty string), properly simulate JDK 9+ behavior
by creating a temp directory with java9-rt-ext- prefix and a
dummy rt.jar inside it.
**Problem**
1. It's difficult to find out when Process fails.
2. global.base setting isn't needed in sbt runner script.
**Solution**
1. Forward to stderr as it happens.
2. Remove global.base setting in the runner script.
**Problem**
After PR #8730 (commit 921efce), inline comments in .jvmopts and .sbtopts files cause errors.
For example, `--add-opens=java.base/java.util=ALL-UNNAMED # comment` results in:
Error: Could not find or load main class #
The # and everything after it is now parsed as separate arguments instead of being stripped as a comment.
**Solution**
Update the sed command in outputConfigFileTokens() to strip inline comments (everything from # to end of line) before parsing tokens.
The new s/\s*\#.*// pattern matches optional whitespace + # + rest of line and removes it.
Generated-by: Claude Sonnet 4.5
**Problem**
The sbt launcher script used naive word splitting when parsing `.sbtopts` and `.jvmopts`, so arguments with spaces were split incorrectly. For example, `-J--add-modules jdk.incubator.concurrent` in `.sbtopts` and `-Dtest.key="value with spaces"` in `.jvmopts` were not passed to the JVM as intended.
**Problem**
`sbt --version` in sbt 2.x project directories was delegated to the native client, which could try to start/connect to a server instead of printing version info.
**Solution**
Skip native-client delegation when `--version` is requested, and add runner-script tests for sbt 1.x and 2.x project variants.
When in an sbt 2.x project directory, the script used to delegate to sbtn
before checking --script-version, so 'sbt --script-version' ran sbtn and
failed. Now we print the script version and exit before the native client
branch.
**Problem**
Apparently sbt can fail when it doesn't have rm,
which can happen "when building relocatable RPM's and building an OS image in a chroot."
**Solution**
It was suggested that we require coreutils.
According to the issue, `.sbtopts` entries are appended after
CLI args in sbt 1.12.x, so `.sbtopts` JVM memory settings (e.g., `-Xmx2g`) override CLI `--mem`,
causing invalid JVM settings.