quarkusio/quarkus · error · SpiffeConnectionException
SPIFFE ID must not contain a port: ${spiffeId}
Error message
SPIFFE ID must not contain a port: ${spiffeId} What it means
The Quarkus SPIFFE client validates every SPIFFE ID against the SPIFFE standard (spiffe://<trust-domain>/<path>) and rejects any URI containing components outside the scheme/host/path form. A port in the authority (e.g. spiffe://trustdomain:8443/ns/default) is not permitted, so SpiffeValidator.validateSpiffeId throws SpiffeConnectionException when URI.getPort() != -1.
Source
Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java:93
if (!spiffeId.startsWith(SPIFFE_URI_PREFIX)) {
throw new SpiffeConnectionException("SPIFFE ID must have 'spiffe://' scheme: " + spiffeId);
}
if (spiffeId.contains("%")) {
throw new SpiffeConnectionException("SPIFFE ID must not contain percent-encoded characters: " + spiffeId);
}
URI uri;
try {
uri = URI.create(spiffeId);
} catch (IllegalArgumentException e) {
throw new SpiffeConnectionException("SPIFFE ID is not a valid URI: " + spiffeId, e);
}
if (uri.getUserInfo() != null) {
throw new SpiffeConnectionException("SPIFFE ID must not contain userinfo: " + spiffeId);
}
if (uri.getPort() != -1) {
throw new SpiffeConnectionException("SPIFFE ID must not contain a port: " + spiffeId);
}
if (uri.getQuery() != null) {
throw new SpiffeConnectionException("SPIFFE ID must not contain a query: " + spiffeId);
}
if (uri.getFragment() != null) {
throw new SpiffeConnectionException("SPIFFE ID must not contain a fragment: " + spiffeId);
}
String trustDomain = uri.getHost();
if (trustDomain == null || trustDomain.isEmpty()) {
throw new SpiffeConnectionException("SPIFFE ID must have a non-empty trust domain: " + spiffeId);
}
if (trustDomain.length() > MAX_TRUST_DOMAIN_LENGTH) {
throw new SpiffeConnectionException("SPIFFE ID trust domain exceeds maximum length of "
+ MAX_TRUST_DOMAIN_LENGTH + " bytes: " + spiffeId);
}
for (int i = 0; i < trustDomain.length(); i++) {
char c = trustDomain.charAt(i);View on GitHub (pinned to e1c734241f)
Solutions
- Remove the ':port' suffix so the ID is spiffe://<trust-domain>/<path>
- Keep connection endpoints (host:port) in the connection config, not in the SPIFFE ID itself
- Fix the registration entry in the SPIRE/workload registrar so its SPIFFE ID SAN has no port
- Pre-validate IDs with URI.create(id).getPort() == -1 before use
Example fix
// before String spiffeId = "spiffe://example.org:8443/ns/default/sa/app"; // after String spiffeId = "spiffe://example.org/ns/default/sa/app";
Defensive patterns
Strategy: validation
Validate before calling
static boolean hasNoPort(String id) {
try { return id.startsWith("spiffe://") && URI.create(id).getPort() == -1; }
catch (IllegalArgumentException e) { return false; }
} Try / catch
try { validator.validateSpiffeId(id); } catch (SpiffeConnectionException e) { log.errorf("Invalid SPIFFE ID %s: %s", id, e.getMessage()); } Prevention
- Never embed host:port endpoint strings in SPIFFE ID fields
- Keep ports in connection configuration, not identity strings
- Add a unit test asserting URI.create(id).getPort() == -1 for all configured IDs
When it happens
Trigger: Passing a SPIFFE ID string containing ':<port>' after the trust domain to validateSpiffeId, or configuring a workload endpoint/certificate whose URI SAN embeds a port (e.g. spiffe://example.org:8080/service).
Common situations: Copy-pasting an HTTPS endpoint URL style into a SPIFFE ID field; hand-writing SPIFFE IDs with cluster agent ports appended; workloads registered with a SPIFFE ID generated from a full server URL including :8443/:443.
Related errors
- SPIFFE ID must not contain a query:
- SPIFFE ID must not contain a fragment:
- SPIFFE ID exceeds maximum length of 2048 bytes: ${length}
- SPIFFE ID must have 'spiffe://' scheme: ${spiffeId}
- SPIFFE ID is not a valid URI: ${spiffeId}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/b1e5aa3dfc65643f.
Report an issue: GitHub.