quarkusio/quarkus · error · SpiffeConnectionException
SPIFFE ID must have a non-root path:
Error message
SPIFFE ID must have a non-root path:
What it means
A SPIFFE ID must include a workload path after the trust domain; 'spiffe://example.org' or 'spiffe://example.org/' identifies nothing. SpiffeValidator.validateSpiffeId throws SpiffeConnectionException when URI.getPath() is null, empty, or just '/'.
Source
Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeValidator.java:120
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);
if (!isValidTrustDomainChar(c)) {
throw new SpiffeConnectionException(
"SPIFFE ID trust domain contains invalid character '" + c + "': " + spiffeId);
}
}
String path = uri.getPath();
if (path == null || path.isEmpty() || "/".equals(path)) {
throw new SpiffeConnectionException("SPIFFE ID must have a non-root path: " + spiffeId);
}
if (path.endsWith("/")) {
throw new SpiffeConnectionException("SPIFFE ID path must not have a trailing slash: " + spiffeId);
}
String[] segments = path.split("/", -1);
for (int i = 1; i < segments.length; i++) {
String segment = segments[i];
if (segment.isEmpty()) {
throw new SpiffeConnectionException(
"SPIFFE ID path must not contain empty segments: " + spiffeId);
}
if (".".equals(segment) || "..".equals(segment)) {
throw new SpiffeConnectionException(
"SPIFFE ID path must not contain dot segments: " + spiffeId);
}
for (int j = 0; j < segment.length(); j++) {
char c = segment.charAt(j);
if (!isValidPathChar(c)) {View on GitHub (pinned to e1c734241f)
Solutions
- Append the workload path, e.g. spiffe://example.org/ns/default/sa/app
- Verify the SVID certificate's URI SAN includes a path component
- Check config/templates so the full ID (domain + path) is generated, not just the domain
Example fix
// before String spiffeId = "spiffe://example.org/"; // after String spiffeId = "spiffe://example.org/ns/default/sa/app";
Defensive patterns
Strategy: validation
Validate before calling
static boolean hasWorkloadPath(String id) {
try {
String p = URI.create(id).getPath();
return p != null && p.length() > 1;
} catch (IllegalArgumentException e) { return false; }
} Try / catch
try { validator.validateSpiffeId(id); } catch (SpiffeConnectionException e) { throw new IllegalStateException("SPIFFE ID needs a workload path", e); } Prevention
- Always generate full IDs including /ns/<ns>/sa/<sa> style paths
- Never use a bare trust domain as a workload identity
When it happens
Trigger: validateSpiffeId invoked with 'spiffe://example.org' or 'spiffe://example.org/' — IDs taken from a CA certificate or config that only names the trust domain.
Common situations: Using the trust domain alone as a workload identity; truncated IDs from config placeholders; constructing the ID without the /ns/<namespace>/sa/<service-account> suffix expected by Kubernetes-style registries.
Related errors
- SPIFFE ID path must not have a trailing slash:
- SPIFFE ID path must not contain empty segments:
- SPIFFE ID path must not contain dot segments:
- SPIFFE ID must not contain a port: ${spiffeId}
- SPIFFE ID must not contain a query:
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/18cc944494ccf513.
Report an issue: GitHub.