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

  1. Remove the ':port' suffix so the ID is spiffe://<trust-domain>/<path>
  2. Keep connection endpoints (host:port) in the connection config, not in the SPIFFE ID itself
  3. Fix the registration entry in the SPIRE/workload registrar so its SPIFFE ID SAN has no port
  4. 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

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


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/b1e5aa3dfc65643f. Report an issue: GitHub.