Docs menu
Troubleshooting Scala
The build and runtime errors Scala apps hit most on Primcloud, with the fix for each.
On this page
Two places to look when a deploy misbehaves:
- Build log: the Deployments tab streams the full build output, including sbt's own compile errors and stack traces.
- Runtime log: the Logs tab streams
stdoutandstderrfrom your running pods. Startup crashes, unhandled exceptions, and JNI load failures show up here.
The errors below run roughly in the order they'd bite you: detection, version resolution, sbt configuration, the sbt build, then runtime.
Build errors#
No Scala application found#
Primcloud looked for *.sbt, project/build.properties, or a .scala file under project/ or .sbt/ at the repo root and found none.
Fix. Move build.sbt and the project/ directory to the repo root, or open a monorepo subdirectory as its own Primcloud app.
No sbt version defined#
project/build.properties is missing, or it exists but doesn't set sbt.version. Primcloud needs an explicit sbt version to run the build.
Fix. Create project/build.properties with:
sbt.version=1.11.7
Use whatever 1.x or 2.x release your build was developed against. See Runtime versions for the supported range.
Unsupported sbt version#
The sbt.version is outside the 1.x and 2.x series, or it's exactly 2.0.0, which Primcloud rejects, because upstream sbt has a plugin-loading bug in that release.
Fix. Bump to a supported version: the latest 1.x for stability, or 2.0.1 or later on the 2.x line.
Unexpected version parse error#
The sbt.version in project/build.properties isn't a valid version, often a typo (1.11..7) or a build tag pasted in whole.
Fix. Use a plain MAJOR.MINOR.PATCH value. Run sbt --version locally to see what your project resolves to.
Unsupported OpenJDK version#
The java.runtime.version in system.properties doesn't match a version Primcloud can install: either an unrecognized major or a patch that isn't available.
Fix. Set it to a supported major (such as 17, 21, or 25) or a specific patch listed in Runtime versions. Pinning a major is usually safer than a patch, since new patches ship automatically.
stage task not found#
Your build.sbt doesn't define a stage task. Most Scala apps get one from sbt-native-packager, but a bare sbt project won't.
Fix. Enable sbt-native-packager:
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.11.7")
enablePlugins(JavaAppPackaging)
Or define a stage task yourself:
lazy val stage = taskKey[Unit]("Stage task")
stage := (Compile / compile).value
Or override the default tasks; see Customizing the build → Task and project overrides.
sbt build hit an out-of-memory error#
Large multi-project builds, heavy annotation-processor plugins, or a build that holds the whole dependency graph in memory can exhaust sbt's heap.
Fix. Give sbt a larger heap through SBT_OPTS:
Set in the Secrets panel:
SBT_OPTS=-J-Xmx2g -J-Xss4m
Could not parse list / Could not parse boolean#
The value for SBT_TASKS, SBT_PRE_TASKS, SBT_CLEAN, or SBT_AVAILABLE_AT_LAUNCH didn't parse.
Fix. For task lists, use plain space-separated names, with no quotes unless a name contains a space. For booleans, use exactly true or false.
Resolver returned 401 Unauthorized#
sbt reached your private Maven or Ivy repository but the credentials didn't authenticate.
Fix. See Package managers → Private packages and registries. The usual causes:
- The
Credentials(realm, host, user, pass)realm doesn't match the repo'sWWW-Authenticateheader. - The environment variables holding the credentials aren't set on the environment the build runs in.
- The token has expired or been rotated.
Runtime errors#
App doesn't bind to $PORT#
Symptom: the deployment reaches Release Succeeded, but the URL returns a connection error and the runtime log has no "listening on" line.
Fix. Confirm the web process binds to $PORT. For Play, the standard Procfile line does it:
web: target/universal/stage/bin/my-app -Dhttp.port=${PORT}
For Akka HTTP, http4s, and other frameworks, read PORT from the environment and pass it to the server binder:
val port = sys.env.getOrElse("PORT", "8080").toInt
A hardcoded port (like 9000) never sees traffic. Primcloud routes to $PORT on the web formation.
UnsatisfiedLinkError at runtime#
java.lang.UnsatisfiedLinkError: no libfoo in java.library.path
Your code, or a JNI-bound library, needs an OS-level shared library that isn't in the run image.
Fix. Install it as a Debian package; see Customizing the build → Debian packages. For libpq5, libmariadb-dev, and similar, add the package name to project.toml and redeploy. If you're unsure of the name, check it with apt search <library> in an Ubuntu 24.04 container.
App exits immediately on start#
The runtime log shows the process starting, then exiting non-zero with little else.
Most common causes:
- An exception before the logger is up. Wrap
mainin a try/catch that writes the exception toSystem.errbefore rethrowing, redeploy, and read the stack trace in the runtime log. - A missing environment variable. If your app reads a database URL or API key and throws on null, set it in the Secrets panel and redeploy.
- Wrong
binname in theProcfile. If theProcfileinvokestarget/universal/stage/bin/wrong-name, that file doesn't exist and the launcher exits at once.sbt-native-packagernames the output from yournameinbuild.sbt, lowercased, with spaces turned to hyphens. - Out of memory at startup. A large static initialization can use more memory than the compute size has, and an app that does is restarted. Move to a larger compute size.
Slow startup / cold-start timeouts#
Scala's JVM warmup runs longer than most languages, and Play compiles its routing table on the first request. If health checks time out on the first deploy after a quiet period:
Fix. Warm the JVM before it takes traffic by hitting an internal health-check endpoint from your entrypoint, or move to a larger compute size, since more CPU means faster JIT.
Debugging tips#
- Reproduce locally with the same command.
sbt compile stageon your machine mirrors what Primcloud runs, provided your local JDK matchessystem.properties. Most build failures reproduce this way. - Check the resolved versions. The build log prints exactly which sbt and JDK got installed. Compare them against
project/build.propertiesandsystem.properties. - Turn on sbt debug logging. Set
SBT_OPTS=-J-Dsbt.log.noformat=true -J-Dsbt.log.level=debugin the Secrets panel temporarily. The log gets noisier, but resolution and task-graph errors gain a lot of detail. - Inspect the staged output. Add a small sbt task that lists
target/universal/stage/afterstageruns, and hook it in throughSBT_PRE_TASKS. It costs a deploy but shows exactly what lands in the image and what yourProcfileshould invoke. - Expect one slow deploy after a version bump. Bumping sbt, Scala, or the JDK invalidates the matching cache. The next deploy is slower; the one after is fast again.