On-Prem Troubleshooting
Common build and deploy errors in air-gapped on-prem environments — Nexus mirror, internal CA, Docker registry, WAS, JDK, settings.xml, RBAC, approval gate
This page is a troubleshooting guide for common build and deploy errors when adopting collabops in air-gapped on-prem environments (government, finance). Each entry shows symptom, cause, and fix across categories like internal Nexus, certificates, JDK versions, and WAS deployment.
1. Dependencies / Nexus mirror
Could not transfer artifact — Maven Central blocked
Symptom: [ERROR] Failed to execute goal ... Could not transfer artifact com.example:foo:pom:1.0.0 from/to central (https://repo.maven.apache.org/maven2): Connection refused
Cause: Air-gapped environments block direct access to Maven Central. settings.xml has no mirror, so Maven tries the default Central URL.
<!-- settings.xml -->
<mirrors>
<mirror>
<id>nexus-internal</id>
<name>Internal Nexus</name>
<url>https://<nexus-host>/repository/maven-public</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>401 Unauthorized — missing Nexus server credentials
Symptom: Authentication failed for ... 401 Unauthorized
Cause: settings.xml has the mirror but no matching server credentials. The server id must match the mirror id for Maven to apply auth.
<servers>
<server>
<id>nexus-internal</id>
<username>${env.NEXUS_USERNAME}</username>
<password>${env.NEXUS_PASSWORD}</password>
</server>
</servers>2. Certificates / internal CA
PKIX path building failed — internal CA missing in truststore
Symptom: javax.net.ssl.SSLHandshakeException: ... PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Cause: The internal CA certificate is not in the JDK cacerts truststore, so Maven / Gradle cannot trust the private Nexus HTTPS cert.
# Import the internal CA into the JDK truststore
keytool -import -trustcacerts \
-alias corp-ca \
-file /path/to/corp-ca.crt \
-keystore $JAVA_HOME/lib/security/cacerts \
-storepass changeit -noprompt
# For container builds, do the same in the Dockerfile
# COPY corp-ca.crt /tmp/
# RUN keytool -import -trustcacerts -alias corp-ca \
# -file /tmp/corp-ca.crt \
# -keystore $JAVA_HOME/lib/security/cacerts \
# -storepass changeit -noprompt3. Docker registry / air-gapped
no such host: registry-1.docker.io — Docker Hub blocked
Symptom: Error response from daemon: pull access denied for maven, repository does not exist or may require 'docker login': no such host: registry-1.docker.io
Cause: Air-gapped environments cannot reach Docker Hub. The Dockerfile base image still points to Docker Hub.
# Route through the internal Harbor mirror
ARG HARBOR_URL
FROM ${HARBOR_URL}/library/maven:3.9-eclipse-temurin-17 AS build
# ...
FROM ${HARBOR_URL}/library/eclipse-temurin:17-jreunauthorized: authentication required — missing Harbor auth
Symptom: Error response from daemon: unauthorized: authentication required
Cause: Harbor robot account credentials are missing or expired. The docker-build-push template cannot find .docker/config.json in the build context.
# Add a harbor-login step in pipeline.yaml (see the java-spring-boot-harbor-image starter-workflow on Marketplace)
- name: harbor-login
image: alpine:3.19
env:
HARBOR_URL: "${{ secrets.HARBOR_URL }}"
HARBOR_USERNAME: "${{ secrets.HARBOR_USERNAME }}"
HARBOR_PASSWORD: "${{ secrets.HARBOR_PASSWORD }}"
run: |
set -euo pipefail
auth=$(printf '%s:%s' "$HARBOR_USERNAME" "$HARBOR_PASSWORD" | base64 | tr -d '\n')
mkdir -p /workspace/source/.docker
printf '{"auths":{"%s":{"auth":"%s"}}}' "$HARBOR_URL" "$auth" \
> /workspace/source/.docker/config.json4. WAS deployment (Tomcat / WebLogic / JEUS)
NoClassDefFoundError: jakarta/servlet/Filter — external Tomcat conflict
Symptom: java.lang.NoClassDefFoundError: jakarta/servlet/Filter (or javax.servlet.* not found)
Cause: The WAR was built with spring-boot-starter-tomcat in compile scope, so its servlet classes clash with the external Tomcat. The Servlet API must come from the external WAS.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>context root exposes the ##version suffix
Symptom: After Tomcat parallel deployment, the URL looks like /app##20260518000000/ (intended: /app).
Cause: Wrong WAR filename format. With <context-root>##<version>.war, only the part before ## is the context root. If the WAR is named incorrectly, the ##version leaks into the URL.
# WAR filename format: <context-root>##<version>.war
# e.g. webapps/app##20260518000000.war → context root = /app
cp /tmp/app.war "${CATALINA_BASE}/webapps/app##$(date -u +%Y%m%d%H%M%S).war"5. Java / JDK version
UnsupportedClassVersionError — compile / runtime JDK mismatch
Symptom: java.lang.UnsupportedClassVersionError: ... has been compiled by a more recent version of the Java Runtime (class file version 61), this version of the Java Runtime only recognizes class file versions up to 55
Cause: Compiled with JDK 17 (class file 61) but executed on JDK 11 (class file 55). Build image and runtime image have different JDK majors.
<!-- pom.xml -->
<properties>
<java.version>17</java.version>
</properties>
<!-- Use the same JDK major in the runtime image -->
<!-- FROM ${HARBOR_URL}/library/eclipse-temurin:17-jre -->Spring Boot 3 — missing javax → jakarta migration
Symptom: After upgrading to Spring Boot 3.x, package javax.servlet does not exist or other import errors.
Cause: Spring Boot 3 uses Jakarta EE 9+, which renames javax.* packages to jakarta.*. Code still importing javax.* fails to compile.
// Before (Spring Boot 2.x)
import javax.servlet.http.HttpServletRequest;
import javax.persistence.Entity;
import javax.validation.constraints.NotNull;
// After (Spring Boot 3.x)
import jakarta.servlet.http.HttpServletRequest;
import jakarta.persistence.Entity;
import jakarta.validation.constraints.NotNull;
// Use OpenRewrite recipes or IDE refactoring for bulk replacement6. Maven settings.xml
mvn deploy 401 — distributionManagement id mismatch
Symptom: On mvn deploy: Failed to deploy artifacts: Could not transfer artifact ... 401 Unauthorized
Cause: The <id> under pom.xml <distributionManagement> does not match any <server><id> in settings.xml. Maven cannot pick the right credentials.
<!-- pom.xml -->
<distributionManagement>
<repository>
<id>nexus-internal</id> <!-- must match -->
<url>https://<nexus-host>/repository/maven-releases</url>
</repository>
</distributionManagement>
<!-- settings.xml -->
<servers>
<server>
<id>nexus-internal</id> <!-- ← same id as above -->
<username>${env.NEXUS_USERNAME}</username>
<password>${env.NEXUS_PASSWORD}</password>
</server>
</servers>7. Permissions / RBAC
Insufficient workflow execution permission — workspace role / branch protection
Symptom: A push does not create a workflow run, or manual execution returns 'permission denied'.
Cause: The actor lacks the required workspace role, or main is a protected branch without direct push access, or the workflow trigger's branches filter does not match.
# Check, in order:
# 1. workspace role: member / maintainer / owner — which level the actor has
# 2. branch protection: is direct push to main allowed, or must changes go through a CR
# 3. workflow triggers branches / tags filters — do they match the actual push
# If permission is insufficient, ask the workspace admin to raise the role or change branch protection8. Approval gate (workflow_dispatch)
workflow_dispatch blocked — actor not in allowlist
Symptom: On prd workflow_dispatch, the verify-actor step emits a permission-denied error (printed in Korean): ERROR: <user> 는 prd 배포 권한이 없습니다
Cause: The verify-actor step of the java-spring-boot-multienv-promote starter-workflow (Marketplace) compares the executor's username against workspace vars PRD_DEPLOY_ALLOWED_ACTORS. The current actor is not on the list.
# Ask a workspace admin to add your username to PRD_DEPLOY_ALLOWED_ACTORS
# before: vars.PRD_DEPLOY_ALLOWED_ACTORS = "alice,bob,charlie"
# after: vars.PRD_DEPLOY_ALLOWED_ACTORS = "alice,bob,charlie,dave"
# A first-class step-level approval gate (reviewer group / timeout / audit log)
# is planned for after collabops workflow environment protections land