Docs menu

Troubleshooting Java

Common build and runtime errors for Java apps 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 output from Maven or Gradle. Build errors and compiler errors surface here.
  • Runtime log: the Logs tab streams stdout and stderr from your running pods. Startup crashes, unhandled exceptions, and JVM messages show up here.

The errors below run in roughly the order they'd bite you: detection, JDK selection, dependency resolution, build failures, then runtime.

Common build errors#

No Java application found#

Primcloud looked for a Maven POM (pom.xml, pom.atom, pom.clj, pom.groovy, pom.rb, pom.scala, pom.yaml, pom.yml) or a Gradle build file (build.gradle, settings.gradle, build.gradle.kts, settings.gradle.kts) at the repo root and found neither.

Fix. Move the POM or build file to the repo root, or open a monorepo subdirectory as its own Primcloud app.

Unsupported OpenJDK version#

system.properties pins java.runtime.version to something that isn't available: a typo (21.0), a major that isn't shipped, or a patch that never existed.

Fix. Set java.runtime.version to a supported major (such as 17, 21, or 25) or a specific patch of one; see Runtime versions. Prefer the major alone (for example 21) unless you have a reason to lock the patch, since Primcloud picks the newest patch automatically.

Invalid system.properties format#

The file has lines the properties parser rejects, or java.runtime.version has no value.

Fix. system.properties is Java properties format: one key=value per line, no leading spaces, # for comments, no quotes around values.

system.properties
java.runtime.version=21
maven.version=3.9.4

Maven wrapper missing or not executable#

Primcloud sees .mvn/wrapper/maven-wrapper.properties but mvnw is missing, or mvnw is present without the executable bit.

Fix. Regenerate the wrapper locally with mvn wrapper:wrapper and commit mvnw, mvnw.cmd, and the .mvn/ directory. If mvnw is missing the executable bit, add it with git update-index --chmod=+x mvnw, commit, and push.

Gradle wrapper missing#

Gradle apps require the wrapper. If gradlew or gradle/wrapper/gradle-wrapper.jar is missing, the build can't run.

Fix. Run gradle wrapper in the repo root, then commit gradlew, gradlew.bat, and the entire gradle/wrapper/ directory.

Maven dependency resolution failed#

Maven exits with Could not find artifact or Could not transfer artifact. Common causes:

  • The dependency lives in a private repository the build can't reach.
  • The version is wrong or was unpublished.
  • The repository is temporarily unreachable.

Fix. For private repositories, confirm settings.xml is at the repo root (or MAVEN_SETTINGS_PATH points at it) and that the credential env vars it references are set; see Package managers. For version issues, resolve locally with ./mvnw dependency:resolve and adjust the POM. For a transient outage, redeploy.

Maven build ran out of memory#

Symptom: java.lang.OutOfMemoryError: Java heap space or GC overhead limit exceeded during compilation.

Fix. Raise the Maven JVM heap by setting MAVEN_JAVA_OPTS to a higher -Xmx, for example -Xmx2048m. The default is -Xmx1024m. If you also need more metaspace: -Xmx2048m -XX:MaxMetaspaceSize=512m.

Gradle stage task not defined#

The default Gradle task is stage. If your build.gradle doesn't define it, Gradle exits with Task 'stage' not found.

Fix. Define a stage task in your build script (usually depending on installDist, bootJar, or shadowJar for your framework), or set GRADLE_TASK in the Secrets panel to the task you actually want.

build.gradle
task stage(dependsOn: ['clean', 'installDist'])

Common 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 "Tomcat started on port" or equivalent line.

Fix. Confirm the web process binds to the port in $PORT, which Primcloud sets to 5000.

For Spring Boot, pass -Dserver.port=$PORT in the Procfile:

Procfile
web: java -Dserver.port=$PORT -jar target/myapp-0.0.1-SNAPSHOT.jar

For Micronaut, -Dmicronaut.server.port=$PORT. For Quarkus, -Dquarkus.http.port=$PORT. For a plain main method, read System.getenv("PORT") and bind to it explicitly.

OutOfMemoryError at runtime#

Symptom: the process starts fine, then hits java.lang.OutOfMemoryError: Java heap space under load.

Fix. Size the heap to your compute plan by setting JAVA_TOOL_OPTIONS in the Secrets panel, for example -XX:MaxRAMPercentage=75 to give the JVM most of the pod's memory, or an explicit -Xmx. If the app genuinely needs more memory, move to a larger compute size. The JVM prints its effective flags at startup, so watch the runtime log after redeploying.

Missing native library at runtime#

java.lang.UnsatisfiedLinkError: no jemalloc in java.library.path

Your code, or a JAR-bundled native, needs an OS-level shared library that isn't in the run image.

Fix. Install it via project.toml; see Customizing the build. For libjemalloc2, libpq5, and similar, add the package name and redeploy.

SSLHandshakeException connecting to a private CA#

Your Java code opens an HTTPS connection to a host whose certificate is signed by a private CA that isn't in the JDK's default trust store.

Fix. Bundle a trust store in your repo and point the JVM at it; see Customizing the build. Public CAs work out of the box.

App exits immediately on start#

The runtime log shows the JVM starting, then exiting with a non-zero code and no useful output.

Most common causes:

  • Missing required env var. Spring Boot, Micronaut, and Quarkus apps often fail fast on a missing datasource URL, API key, or profile flag. Set the required env var in the Secrets panel and redeploy.
  • Wrong artifact path in Procfile. If the JAR name doesn't match the pattern in the Procfile (a version bump from 1.0.0 to 1.1.0, say), the JVM can't find it and exits. Rename the JAR in your build (Maven <finalName>, Gradle archivesBaseName) or update the Procfile.
  • Incompatible bytecode version. Class files compiled against a newer JDK than the one running produce UnsupportedClassVersionError (you built locally with 21, the deploy uses 17). Pin the same JDK in system.properties that you build with locally.

Debugging tips#

  • Reproduce locally with the build command. ./mvnw clean install -DskipTests or ./gradlew stage on your machine mirrors what Primcloud runs. Most build failures reproduce this way.
  • Check the resolved JDK. The build log prints the exact OpenJDK version installed. Compare it against system.properties. If you set 21 and see a 17 build, system.properties isn't being read (typo, or wrong path).
  • Turn up Maven verbosity temporarily. Set MAVEN_CUSTOM_OPTS=-DskipTests -X, redeploy, then unset once you've isolated the issue. The Gradle equivalent is GRADLE_TASK=stage --info (or --debug).
  • Confirm the launch command. In the Procfile, echo the command before running it: web: bash -c 'echo java -Dserver.port=$PORT -jar target/*.jar && exec java -Dserver.port=$PORT -jar target/*.jar'. The exec matters: without it, java runs as a child of bash and signals don't propagate cleanly.
  • Check the effective JVM options. Add -XX:+PrintFlagsFinal -version to a temporary Procfile command to dump every JVM flag with its source. Cheaper than guessing at what JAVA_TOOL_OPTIONS ended up as.